Android 10.0 Launcher3拖拽图标进入hotseat自适应布局功能实现五

1.前言

在10.0的系统rom定制化开发中,在对于launcher3的一些开发定制中,在对hotseat的一些开发中,需要实现动态hotseat居中 的功能,就是在拖拽图标进入和拖出hotseat,都可以保持hotseat居中的功能,接下来分析下相关功能实现 具体如图:

hotseat

2.Launcher3拖拽图标进入hotseat自适应布局功能实现五的核心类

packages\apps\Launcher3\src\com\android\launcher3\Launcher.java
packages/apps/Launcher3/src/com/android/launcher3/Workspace.java

3.Launcher3拖拽图标进入hotseat自适应布局功能实现四的核心功能分析和实现

Launcher顾名思义,就是桌面的意思,也是android系统启动后第一个启动的应用程序, :Launcher3负责管理和展示用户手机桌面上的各个应用程序图标。它通过GridView或者LinearLayout等布局管理器将 图标进行排列,并支持滑动、放大缩小等手势操作 Hotseat也是属于在导航栏底部的BubbleTextView的布局,只是不显示app图标 CellLayout:主屏幕中的每一页,其父布局就是Workspace,左右滑动屏幕,就是每一个CellLayout的变化过程,这个类中有很多处理拖拽相关方法 Workspace:就是CellLayout的父布局,所有的桌面app图标 hotseat图标 folder文件夹 widget小部件都是显示在workspace上的

3.1 Launcher.java中关于hotseat居中的一些相关功能实现

在实现Launcher3拖拽图标进入hotseat自适应布局功能实现四的核心功能中,通过上述的分析得知, 在Launcher.java中主要就是Launcher3的核心类,加载数据绑定数据等,在这里同样也需要调用 LauncherAppMonitor实现hotseat数据变化监听功能,具体实现如下

diff --git a/packages/apps/Launcher3/src/com/android/launcher3/Launcher.java b/packages/apps/Launcher3/src/com/android/launcher3/Launcher.java
index ef62991f8cd..41caf428568 100755
--- a/packages/apps/Launcher3/src/com/android/launcher3/Launcher.java
+++ b/packages/apps/Launcher3/src/com/android/launcher3/Launcher.java
@@ -200,6 +200,8 @@ import java.util.stream.Stream;
 //add code start
 import android.provider.Settings;
 import android.view.Surface;
+import com.android.launcher3.util.LauncherAppMonitor;
+import com.android.launcher3.util.HotseatController;
 //add code end
 /**
  * Default launcher application.
@@ -366,7 +368,10 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
         }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-
+        //add core start
+               mAppMonitor = LauncherAppMonitor.getInstance(this);
+               mAppMonitor.onLauncherCreated();
+               //add core end
         LauncherAppState app = LauncherAppState.getInstance(this);
         mOldConfig = new Configuration(getResources().getConfiguration());
         mModel = app.getModel();
@@ -444,7 +449,6 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
                 OverlayPlugin.class, false /* allowedMultiple */);
 
         mRotationHelper.initialize();
-
         mStateManager.addStateListener(new StateListener<LauncherState>() {
 
    private void handleActivityResult(
            final int requestCode, final int resultCode, final Intent data) {
-
+               //add core start
+        HotseatController hc = mHotseat.getController();
+        if (hc != null) {
+            hc.setDelayClearEmptyGridFlag(false);
+            hc.clearEmptyGrid(this);
+        }
+               //add core end
         mDragLayer.clearAnimatedView();
     }
 
@@ -804,6 +814,9 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
     public void onRequestPermissionsResult(int requestCode, String[] permissions,
             int[] grantResults) {
         PendingRequestArgs pendingArgs = mPendingRequestArgs;
+               //add core start
+        mAppMonitor.onLauncherRequestPermissionsResult(requestCode, permissions, grantResults);
+               //add core end
         if (requestCode == REQUEST_PERMISSION_CALL_PHONE && pendingArgs != null
                 && pendingArgs.getRequestCode() == REQUEST_PERMISSION_CALL_PHONE) {
             setWaitingForResult(null);

   @Override
    protected void onStop() {
        super.onStop();
         mAppWidgetHost.setListenIfResumed(false);
         NotificationListener.removeNotificationsChangedListener();
+               //add core start
+         mAppMonitor.onLauncherStop();
+               //add core end
     }
 
    @Override
    protected void onStart() {
-
+               //add core start
+        mAppMonitor.onLauncherStart();
+               //add core end
         mAppWidgetHost.setListenIfResumed(true);
         TraceHelper.INSTANCE.endSection(traceToken);
     }
@@ -1047,6 +1065,9 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
     protected void onResume() {
         Object traceToken = TraceHelper.INSTANCE.beginSection(ON_RESUME_EVT,
                 TraceHelper.FLAG_UI_EVENT);
+        //add core start
+         mAppMonitor.onLauncherPreResume();
+        //add core end
         super.onResume();
 
         if (!mOnResumeCallbacks.isEmpty()) {
@@ -1066,6 +1087,7 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
 
         TraceHelper.INSTANCE.endSection(traceToken);
                //add code start
+        mAppMonitor.onLauncherResumed();
                Settings.System.putInt(getContentResolver(), Settings.System.USER_ROTATION, Surface.ROTATION_90);
                //add code end
     }
@@ -1074,7 +1096,9 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
     protected void onPause() {
         // Ensure that items added to Launcher are queued until Launcher returns
         InstallShortcutReceiver.enableInstallQueue(InstallShortcutReceiver.FLAG_ACTIVITY_PAUSED);
-
+               //add core start
+        mAppMonitor.onLauncherPrePause();
+        //add core end
         super.onPause();
         mDragController.cancelDrag();
         mLastTouchUpTime = -1;
@@ -1083,6 +1107,9 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
         if (!mDeferOverlayCallbacks) {
             mOverlayManager.onActivityPaused(this);
         }
+               //add core start
+        mAppMonitor.onLauncherPaused();
+        //add core end
     }
 
    @Override
    protected void onNewIntent(Intent intent) {
 
         if (isActionMain) {
+                       //add core start
+            mAppMonitor.onReceiveHomeIntent();
+                       //add core end
             if (!internalStateHandled) {
                 // In all these cases, only animate if we're already on home
                 closeOpenViews(isStarted());
@@ -1722,13 +1752,13 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
     public FolderIcon addFolder(CellLayout layout, int container, final int screenId, int cellX,
             int cellY) {
         final FolderInfo folderInfo = new FolderInfo();
-
         // Update the model
         getModelWriter().addItemToDatabase(folderInfo, container, screenId, cellX, cellY);
 
         // Create the view
         FolderIcon newFolder = FolderIcon.inflateFolderAndIcon(R.layout.folder_icon, this, layout,
                 folderInfo);

         mWorkspace.addInScreen(newFolder, folderInfo);

    @Override
    public void bindItems(final List<ItemInfo> items, final boolean forceAnimateIcons) {
+               //add core start
+        if (mHotseat != null) {
+            HotseatController hc = mHotseat.getController();
+            if (hc != null) {
+                hc.clearEmptyGrid(this);
+            }
+        }
+               //add core end
         workspace.requestLayout();
     }
 
    public void finishBindingItems(int pageBoundFirst) {
         getViewCache().setCacheSize(R.layout.folder_application,
                 mDeviceProfile.inv.numFolderColumns * mDeviceProfile.inv.numFolderRows);
         getViewCache().setCacheSize(R.layout.folder_page, 2);
-
+               //add core start
+        mAppMonitor.onLauncherWorkspaceBindingFinish();
+               //add core end
         TraceHelper.INSTANCE.endSection(traceToken);
     }
 
@@ -2460,6 +2500,9 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
     @Override
     public void bindAllApplications(AppInfo[] apps, int flags) {
         mAppsView.getAppsStore().setApps(apps, flags);
+               //add core start
+        mAppMonitor.onLauncherAllAppBindingFinish(apps);
+               //add core end
     }

在实现Launcher3拖拽图标进入hotseat自适应布局功能实现四的核心功能中,通过上述的分析得知,
在Launcher.java中的上述添加的功能中,主要就是调用LauncherAppMonitor实现hotseat数据变化监听功能
和相关hotseat的布局实现

3.2 Workspace.java中相关hotseat功能实现

在实现Launcher3拖拽图标进入hotseat自适应布局功能实现四的核心功能中,通过上述的分析得知,
在Workspace.java中的上述添加的功能中,主要负责hotseat数据绑定的相关功能操作,具体实现如下

diff --git a/packages/apps/Launcher3/src/com/android/launcher3/Workspace.java b/packages/apps/Launcher3/src/com/android/launcher3/Workspace.java
index fd68b6b9003..c6eb0c999f4 100755
--- a/packages/apps/Launcher3/src/com/android/launcher3/Workspace.java
+++ b/packages/apps/Launcher3/src/com/android/launcher3/Workspace.java
@@ -117,7 +117,7 @@ import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverla
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.function.Predicate;
-
+import com.android.launcher3.util.HotseatController;
 /**
  * The workspace is a wide area with a wallpaper and a finite number of pages.
  * Each page contains a number of icons, folders or widgets the user can
@@ -245,7 +245,10 @@ public class Workspace extends PagedView<WorkspacePageIndicatorDots>
     float mLastOverlayScroll = 0;
     boolean mOverlayShown = false;
     private Runnable mOnOverlayHiddenCallback;
-
+       //add core start
+    private boolean mIsNeedUpdateHotseatLayout;
+    private boolean mIsNeedWaitHotseatChanged;
+       //add core end
     private boolean mForceDrawAdjacentPages = false;
 
    @Override
    public void onDragEnd() {
         if (!mDeferRemoveExtraEmptyScreen) {
             removeExtraEmptyScreen(mDragSourceInternal != null);
         }
-
+//add core start
+        HotseatController hc = getHotseat().getController();
+        if (hc != null) {
+            hc.clearEmptyGrid(mLauncher);
+            hc.backupDragInfo(mDragInfo);
+        }
+//add core end
         updateChildrenLayersEnabled();
         mDragInfo = null;
         mOutlineProvider = null;
         mDragSourceInternal = null;
     }
-
+//add core start
+    private void resetDragCellIfNeed(CellLayout.CellInfo dragInfo) {
+        HotseatController hc = getHotseat().getController();
+        if (hc != null) {
+            // Make sure hotseat has no empty grid before reset drag view.
+            hc.clearEmptyGrid(mLauncher);
+            hc.resetDragCell(mLauncher, dragInfo);
+        }
+    }
+//add core end
 
   @Override
    public void onDrop(final DragObject d, DragOptions options) {
         if (dropOverView instanceof FolderIcon) {
             FolderIcon fi = (FolderIcon) dropOverView;
             if (fi.acceptDrop(d.dragInfo)) {
@@ -1767,8 +1782,17 @@ public class Workspace extends PagedView<WorkspacePageIndicatorDots>
             final View cell = mDragInfo.cell;
             boolean droppedOnOriginalCellDuringTransition = false;
             Runnable onCompleteRunnable = null;
-
-            if (dropTargetLayout != null && !d.cancelled) {
+//add core start
+boolean isDrop = true;
+ShortcutAndWidgetContainer mContainer = mLauncher.getHotseat().getShortcutsAndWidgets();
+int childcount = mContainer.getChildCount();
+int drag_container = mDragInfo.container;
+Log.e("Hotseat","childcount:"+childcount+"--drag_container:"+drag_container);
+if(childcount==1&&drag_container==-101){
+       isDrop=false;
+}
+//add core end
+            if (dropTargetLayout != null && !d.cancelled&&isDrop) {
                 // Move internally
                 boolean hasMovedLayouts = (getParentCellLayoutForView(cell) != dropTargetLayout);
                 boolean hasMovedIntoHotseat = mLauncher.isHotseatLayout(dropTargetLayout);
@@ -1898,7 +1922,6 @@ public class Workspace extends PagedView<WorkspacePageIndicatorDots>
                     layout.markCellsAsOccupiedForView(cell);
                 }
             }
-
             final CellLayout parent = (CellLayout) cell.getParent().getParent();
             if (d.dragView.hasDrawn()) {
                 if (droppedOnOriginalCellDuringTransition) {

    @Override
    public void onDragEnter(DragObject d) {
         mDropToLayout = null;
         mDragViewVisualCenter = d.getVisualCenter(mDragViewVisualCenter);
         setDropLayoutForDragObject(d, mDragViewVisualCenter[0], mDragViewVisualCenter[1]);
+               //add core start
+        mIsNeedUpdateHotseatLayout = false;
+        mIsNeedWaitHotseatChanged = false;
+               //add core end
     }
 
     @Override
@@ -2131,7 +2158,49 @@ public class Workspace extends PagedView<WorkspacePageIndicatorDots>
            mapPointFromSelfToChild(layout, xy);
        }
    }
+   //add core start
+    private boolean autoAdaptHotseatLayout(DragObject d, View child) {
+        HotseatController hc = getHotseat().getController();
+        if (hc == null) {
+            return false;
+        }
+
+        boolean hasMovedLayouts = getParentCellLayoutForView(child) != mDragTargetLayout;
+        boolean hasMovedIntoHotseat = mLauncher.isHotseatLayout(mDragTargetLayout);
+        boolean hasMovedFromHotseat = mLauncher.isHotseatLayout(getParentCellLayoutForView(child));
+        if (hasMovedLayouts &&
+                (hasMovedIntoHotseat || hasMovedFromHotseat)) {
+            mIsNeedUpdateHotseatLayout = true;
+        }
+        if (mIsNeedUpdateHotseatLayout) {
+            if (hasMovedIntoHotseat) {
+                if (hc.isFull(mLauncher)) {
+                    int index = hc.calculateBestIndex(mLauncher,
+                            mDragViewVisualCenter, mTargetCell[0], mTargetCell[1]);
+                    mIsNeedWaitHotseatChanged = hc.insertEmptyGrid(mLauncher, index);
+                }
+            } else {
+                if (!hc.isFull(mLauncher)) {
+                    mIsNeedWaitHotseatChanged = hc.clearEmptyGrid(mLauncher);
+                }
+            }
 
+            if (mIsNeedWaitHotseatChanged) {
+                ShortcutAndWidgetContainer sawc = getHotseat().getShortcutsAndWidgets();
+                sawc.addOnLayoutChangeListener(new OnLayoutChangeListener() {
+                    @Override
+                    public void onLayoutChange(View v, int left, int top, int right, int bottom,
+                                               int oldLeft, int oldTop, int oldRight, int oldBottom) {
+                        sawc.removeOnLayoutChangeListener(this);
+                        mIsNeedWaitHotseatChanged = false;
+                    }
+                });
+                return true;
+            }
+        }
+        return false;
+    }
+   //add core end
     private boolean isDragWidget(DragObject d) {
         return (d.dragInfo instanceof LauncherAppWidgetInfo ||
                 d.dragInfo instanceof PendingAddWidgetInfo);


    public void onDragOver(DragObject d) {
                     mDragTargetLayout, mTargetCell);
             int reorderX = mTargetCell[0];
             int reorderY = mTargetCell[1];
-
+//add core start
+            if (autoAdaptHotseatLayout(d, child)) {
+                return;
+            }
+//add core end
             setCurrentDropOverCell(mTargetCell[0], mTargetCell[1]);
 
             float targetCellDistance = mDragTargetLayout.getDistanceFromCell(

    private void onDropExternal(final int[] touchXY, final CellLayout cellLayout, DragObject d) {
                 item.spanX = resultSpan[0];
                 item.spanY = resultSpan[1];
             }
-
+//add core start
+            if (mLauncher.isHotseatLayout(cellLayout)) {
+                HotseatController hc = getHotseat().getController();
+                if (hc != null) {
+                    pendingInfo.rank = hc.getOrderInHotseat(mLauncher, mTargetCell[0], mTargetCell[1]);
+                }
+            }
+//add core end
             Runnable onAnimationCompleteRunnable = new Runnable() {
                 @Override
                 public void run() {

    public void onDropCompleted(final View target, final DragObject d,
            final boolean success) {
         }
         View cell = getHomescreenIconByItemId(d.originalDragInfo.id);
+               //add core start
+        HotseatController hc = getHotseat().getController();
+               //add core end
         if (d.cancelled && cell != null) {
             cell.setVisibility(VISIBLE);
+                       //add core start
+            if (d.originalDragInfo.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT
+                    && hc != null && hc.isCellOccupied(mLauncher)) {
+                getHotseat().onDropChild(cell);
+            } else if (cell.getParent() != null) {
+                CellLayout layout = (CellLayout) cell.getParent().getParent();
+                layout.markCellsAsOccupiedForView(cell);
+            }
+        } else if (d.cancelled) {
+            if (mDragInfo != null) {
+                resetDragCellIfNeed(mDragInfo);
+            } else if (hc != null) {
+                resetDragCellIfNeed(hc.getBackupDragInfo());
+            }
+                       //add core end
         }
         mDragInfo = null;
     }
@@ -2881,7 +2977,7 @@ public class Workspace extends PagedView<WorkspacePageIndicatorDots>
     /**
      * Returns a list of all the CellLayouts on the Homescreen.
      */
-    private CellLayout[] getWorkspaceAndHotseatCellLayouts() {
+    public CellLayout[] getWorkspaceAndHotseatCellLayouts() {
         int screenCount = getChildCount();
         final CellLayout[] layouts;
         if (mLauncher.getHotseat() != null) {


    public void removeItemsByMatcher(final ItemInfoMatcher matcher) {
                     // Note: We can not remove the view directly from CellLayoutChildren as this
                     // does not re-mark the spaces as unoccupied.
                     layoutParent.removeViewInLayout(child);
+                                       //add core start
+                    if (itemToRemove.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
+                        HotseatController hc = getHotseat().getController();
+                        if (hc != null) {
+                            hc.clearEmptyGrid(mLauncher);
+                        }
+                    }
+                                       //add core end
                     if (child instanceof DropTarget) {
                         mDragController.removeDropTarget((DropTarget) child);
                     }

在实现Launcher3拖拽图标进入hotseat自适应布局功能实现四的核心功能中,通过上述的分析得知,
在Workspace.java中的上述添加的功能中,主要负责hotseat数据绑定的相关功能操作,通过上述的
功能添加就完整实现了hotset拖拽始终保持hotseat居中显示的功能实现

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Android 10.0中,Launcher3是一个默认的桌面启动器应用程序。默认情况下,Launcher3使用了多层桌面布局,由于每个应用程序的图标和小部件可以在不同的层级上进行放置,可以实现更多自定义和可玩性。 要将Launcher3修改为单层布局,可以进行以下步骤: 首先,要修改Launcher3的源代码。打开Launcher3的项目文件,在代码中找到与多层布局相关的部分。一般上,这些代码与屏幕上的图标和小部件的位置确定有关。 接下来,需要将多层布局改为单层布局。这意味着所有的图标和小部件将只能放置在一个层级上,不能另行分层。可以将所有图标和小部件视为一个整体,进行单层布局的更改。 在代码中找到与层级相关的代码,并进行相应的修改。可能涉及到图标和小部件的位置计算、绘制和触摸事件等。将多层布局的相关代码注释掉,或者删除,然后添加单层布局的代码。确保所有的图标和小部件都被正确地放置在单个层级上。 最后,重新编译和部署修改后的Launcher3应用程序。确保应用程序可以成功运行,并验证桌面布局是否变为单层。 通过以上步骤,就可以成功地将Android 10.0 Launcher3修改为单层布局。需要注意的是,这种修改可能涉及较多的代码更改,并且需要一定的编程经验和知识。如果对Android开发不熟悉,建议参考相关文档和指南,或咨询专业的开发人员进行帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

安卓兼职framework应用工程师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值