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居中显示的功能实现