• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/**
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import {
17  Log,
18  BaseDragHandler,
19  CommonConstants,
20  CheckEmptyUtils,
21  SettingsModel,
22  EventConstants,
23  localEventManager,
24  layoutConfigManager,
25  PageDesktopModel
26} from '@ohos/common';
27import type {
28  LauncherDragItemInfo,
29  DragArea,
30  DragItemPosition
31} from '@ohos/common';
32import { FormViewModel } from '@ohos/form';
33import { BigFolderViewModel } from '@ohos/bigfolder';
34import { PageDesktopGridStyleConfig } from './PageDesktopGridStyleConfig';
35import PageDesktopConstants from './constants/PageDesktopConstants'
36
37const TAG = 'PageDesktopDragHandler';
38
39/**
40 * Desktop workspace drag and drop processing class
41 */
42export class PageDesktopDragHandler extends BaseDragHandler {
43  private readonly mPageDesktopStyleConfig: PageDesktopGridStyleConfig;
44  private readonly mBigFolderViewModel: BigFolderViewModel;
45  private readonly mFormViewModel: FormViewModel;
46  private readonly mSettingsModel: SettingsModel;
47  private readonly mPageDesktopModel: PageDesktopModel;
48  private mGridConfig;
49  private mPageCoordinateData = {
50    gridXAxis: [],
51    gridYAxis: []
52  };
53  private mStartPosition: DragItemPosition;
54  private mEndPosition: DragItemPosition;
55  private readonly styleConfig;
56  private mGridItemHeight: number;
57  private mGridItemWidth: number;
58
59  private constructor() {
60    super();
61    this.mBigFolderViewModel = BigFolderViewModel.getInstance();
62    this.mSettingsModel = SettingsModel.getInstance();
63    this.mFormViewModel = FormViewModel.getInstance();
64    this.mPageDesktopModel = PageDesktopModel.getInstance();
65    this.mPageDesktopStyleConfig = layoutConfigManager.getStyleConfig(PageDesktopGridStyleConfig.APP_GRID_STYLE_CONFIG,
66      PageDesktopConstants.FEATURE_NAME);
67  }
68
69  static getInstance(): PageDesktopDragHandler {
70    if (globalThis.PageDesktopDragHandler == null) {
71      globalThis.PageDesktopDragHandler = new PageDesktopDragHandler();
72    }
73    return globalThis.PageDesktopDragHandler;
74  }
75
76  setDragEffectArea(effectArea): void {
77    Log.showDebug(TAG, `setDragEffectArea:${JSON.stringify(effectArea)}`)
78    AppStorage.setOrCreate('pageDesktopDragEffectArea', effectArea);
79    super.setDragEffectArea(effectArea);
80    this.updateGridParam(effectArea);
81  }
82
83  isDragEffectArea(x: number, y: number): boolean {
84    const isInEffectArea = super.isDragEffectArea(x, y);
85    Log.showDebug(TAG, `isDragEffectArea x: ${x}, y: ${y}, isInEffectArea: ${isInEffectArea}`);
86    const deviceType: string = AppStorage.get('deviceType');
87    const smartDockDragEffectArea: DragArea = AppStorage.get('smartDockDragEffectArea');
88    Log.showDebug(TAG, `isDragEffectArea smartDockDragEffectArea: ${JSON.stringify(smartDockDragEffectArea)}`);
89    if (smartDockDragEffectArea) {
90      if (deviceType == CommonConstants.DEFAULT_DEVICE_TYPE) {
91        if (isInEffectArea || (y <= smartDockDragEffectArea.bottom && y >= smartDockDragEffectArea.top)
92        && x <= smartDockDragEffectArea.right && x >= smartDockDragEffectArea.left) {
93          return true;
94        }
95        return false;
96      }
97      return isInEffectArea;
98    }
99    return false;
100  }
101
102  getRow(index: number): number {
103    return ~~(index / this.mSettingsModel.getGridConfig().column);
104  }
105
106  getColumn(index: number): number {
107    return index % this.mSettingsModel.getGridConfig().column;
108  }
109
110  private updateGridParam(effectArea: DragArea): void {
111    const gridWidth = this.mPageDesktopStyleConfig.mGridWidth;
112    const gridHeight = this.mPageDesktopStyleConfig.mGridHeight;
113    Log.showDebug(TAG, `updateGridParam gridWidth: ${gridWidth}, gridHeight: ${gridHeight}`);
114    this.mGridConfig = this.mSettingsModel.getGridConfig();
115    const column = this.mGridConfig.column;
116    const row = this.mGridConfig.row;
117    const columnsGap =  this.mPageDesktopStyleConfig.mColumnsGap;
118    const rowGap =  this.mPageDesktopStyleConfig.mRowsGap;
119    this.mGridItemHeight = row > 0 ? (gridHeight + columnsGap) / row : 0;
120    this.mGridItemWidth = column > 0 ? (gridWidth + rowGap) / column : 0;
121    Log.showDebug(TAG, `updateGridParam column: ${column}, row: ${row}`);
122    this.mPageCoordinateData.gridYAxis = [];
123    for (let i = 1; i <= row; i++) {
124      const touchPositioningY = (gridHeight / row) * i + effectArea.top;
125      this.mPageCoordinateData.gridYAxis.push(touchPositioningY);
126    }
127
128    this.mPageCoordinateData.gridXAxis = [];
129    for (let i = 1; i <= column; i++) {
130      const touchPositioningX = (gridWidth / column) * i + effectArea.left;
131      this.mPageCoordinateData.gridXAxis.push(touchPositioningX);
132    }
133  }
134
135  protected getDragRelativeData(): any {
136    const desktopDataInfo: {
137      appGridInfo: [[]]
138    } = AppStorage.get('appListInfo');
139    return desktopDataInfo.appGridInfo;
140  }
141
142  protected getItemIndex(x: number, y: number): number {
143    Log.showInfo(TAG, `getItemIndex x: ${x}, y: ${y}`);
144    let rowVal = CommonConstants.INVALID_VALUE;
145    for (let index = 0; index < this.mPageCoordinateData.gridYAxis.length; index++) {
146      if (this.mPageCoordinateData.gridYAxis[index] > y) {
147        rowVal = index;
148        break;
149      }
150    }
151    let columnVal = CommonConstants.INVALID_VALUE;
152    for (let index = 0; index < this.mPageCoordinateData.gridXAxis.length; index++) {
153      if (this.mPageCoordinateData.gridXAxis[index] > x) {
154        columnVal = index;
155        break;
156      }
157    }
158    const column = this.mGridConfig.column;
159    if (rowVal != CommonConstants.INVALID_VALUE && columnVal != CommonConstants.INVALID_VALUE) {
160      return rowVal * column + columnVal;
161    }
162    return CommonConstants.INVALID_VALUE;
163  }
164
165  protected getItemByIndex(index: number): any {
166    const column = index % this.mGridConfig.column;
167    const row = Math.floor(index / this.mGridConfig.column);
168    const pageIndex: number = AppStorage.get('pageIndex');
169    const appGridInfo = this.getDragRelativeData();
170    Log.showInfo(TAG, `getItemByIndex pageIndex: ${pageIndex}, appGridInfo length: ${appGridInfo.length},
171    column: ${column}, row: ${row}`);
172    const itemInfo = appGridInfo[pageIndex].find(item => {
173      if (item.typeId == CommonConstants.TYPE_APP) {
174        return item.column == column && item.row == row;
175      } else if (item.typeId == CommonConstants.TYPE_FOLDER || item.typeId == CommonConstants.TYPE_CARD) {
176        return this.isItemInRowColumn(row, column, item);
177      }
178    });
179    return itemInfo;
180  }
181
182  /**
183   * judge the item is at target row and column
184   * @param row
185   * @param column
186   * @param item
187   */
188  private isItemInRowColumn(row: number, column: number, item: any): boolean {
189    return item.column <= column && column < item.column + item.area[0] && item.row <= row && row < item.row + item.area[1];
190  }
191
192  private getTouchPosition(x: number, y: number): DragItemPosition {
193    const pageIndex: number = AppStorage.get('pageIndex');
194    Log.showDebug(TAG, `getTouchPosition pageIndex: ${pageIndex}`);
195    const position: DragItemPosition = {
196      page: pageIndex,
197      row: 0,
198      column: 0,
199      X: x,
200      Y: y,
201    };
202    for (let i = 0; i < this.mPageCoordinateData.gridXAxis.length; i++) {
203      if (x < this.mPageCoordinateData.gridXAxis[i]) {
204        position.column = i;
205        break;
206      } else {
207        position.column = this.mPageCoordinateData.gridXAxis.length - 1;
208      }
209    }
210    for (let i = 0; i < this.mPageCoordinateData.gridYAxis.length; i++) {
211      if (y < this.mPageCoordinateData.gridYAxis[i]) {
212        position.row = i;
213        break;
214      } else {
215        position.row = this.mPageCoordinateData.gridYAxis.length - 1;
216      }
217    }
218    return position;
219  }
220
221  onDragStart(x: number, y: number): void {
222    this.mStartPosition = null;
223    Log.showInfo(TAG, `onDragStart start`);
224    const selectAppIndex = this.getItemIndex(x, y);
225    AppStorage.setOrCreate('selectAppIndex', selectAppIndex);
226    this.mStartPosition = this.getTouchPosition(x, y);
227  }
228
229  onDragDrop(x: number, y: number): boolean {
230    const dragItemInfo: LauncherDragItemInfo = AppStorage.get<LauncherDragItemInfo>('dragItemInfo');
231    if (!dragItemInfo.isDragging) {
232      return false;
233    }
234    const dragItemType: number = AppStorage.get('dragItemType');
235    const deviceType: string = AppStorage.get('deviceType')
236    // dock appInfo has no location information.
237    if (dragItemType === CommonConstants.DRAG_FROM_DOCK && deviceType == CommonConstants.DEFAULT_DEVICE_TYPE) {
238      dragItemInfo.typeId = CommonConstants.TYPE_APP;
239      dragItemInfo.area = [1, 1];
240      dragItemInfo.page = AppStorage.get('pageIndex');
241    }
242    Log.showDebug(TAG, `onDragEnd dragItemInfo: ${JSON.stringify(dragItemInfo)}`);
243    const endIndex = this.getItemIndex(x, y);
244    const startPosition: DragItemPosition = this.copyPosition(this.mStartPosition);
245    let endPosition: DragItemPosition = null;
246    this.mEndPosition = this.getTouchPosition(x, y);
247    Log.showDebug(TAG, `onDragEnd mEndPosition: ${JSON.stringify(this.mEndPosition)}`);
248    endPosition = this.copyPosition(this.mEndPosition);
249    const info = this.mSettingsModel.getLayoutInfo();
250    const layoutInfo = info.layoutInfo;
251    if (dragItemInfo.typeId == CommonConstants.TYPE_FOLDER || dragItemInfo.typeId == CommonConstants.TYPE_CARD) {
252      this.updateEndPosition(dragItemInfo);
253    } else {
254      if (this.isMoveToSamePosition(dragItemInfo)) {
255        this.deleteBlankPageAfterDragging(startPosition, endPosition);
256        return false;
257      }
258      const endLayoutInfo = this.getEndLayoutInfo(layoutInfo);
259      if (endLayoutInfo != undefined) {
260        // add app to folder
261        if (endLayoutInfo.typeId === CommonConstants.TYPE_FOLDER) {
262          this.mBigFolderViewModel.addOneAppToFolder(dragItemInfo, endLayoutInfo.folderId);
263          if (dragItemType === CommonConstants.DRAG_FROM_DOCK && deviceType == CommonConstants.DEFAULT_DEVICE_TYPE) {
264            localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_RESIDENT_DOCK_ITEM_DELETE, dragItemInfo);
265          }
266          this.deleteBlankPageAfterDragging(startPosition, endPosition);
267          return true;
268        } else if (endLayoutInfo.typeId === CommonConstants.TYPE_APP) {
269          // create a new folder
270          const layoutInfoList = [endLayoutInfo];
271          let startLayoutInfo = null;
272          if (dragItemType === CommonConstants.DRAG_FROM_DOCK && deviceType == CommonConstants.DEFAULT_DEVICE_TYPE) {
273            let appInfoList = this.mSettingsModel.getAppListInfo();
274            const appIndex = appInfoList.findIndex(item => {
275              return item.keyName === dragItemInfo.keyName;
276            })
277            if (appIndex == CommonConstants.INVALID_VALUE) {
278              appInfoList.push({
279                "appName": dragItemInfo.appName,
280                "isSystemApp": dragItemInfo.isSystemApp,
281                "isUninstallAble": dragItemInfo.isUninstallAble,
282                "appIconId": dragItemInfo.appIconId,
283                "appLabelId": dragItemInfo.appLabelId,
284                "bundleName": dragItemInfo.bundleName,
285                "abilityName": dragItemInfo.abilityName,
286                "moduleName": dragItemInfo.moduleName,
287                "keyName": dragItemInfo.keyName,
288                "typeId": dragItemInfo.typeId,
289                "area": dragItemInfo.area,
290                "page": dragItemInfo.page,
291                "column": this.getColumn(endIndex),
292                "row": this.getRow(endIndex),
293                "x": 0,
294                "installTime": dragItemInfo.installTime
295              })
296              this.mSettingsModel.setAppListInfo(appInfoList);
297            }
298            startLayoutInfo = dragItemInfo;
299            localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_RESIDENT_DOCK_ITEM_DELETE, dragItemInfo);
300          } else {
301            startLayoutInfo = this.getStartLayoutInfo(layoutInfo, dragItemInfo);
302          }
303          layoutInfoList.push(startLayoutInfo);
304          this.mBigFolderViewModel.addNewFolder(layoutInfoList).then(()=> {
305            this.deleteBlankPageAfterDragging(startPosition, endPosition);
306          });
307          return true;
308        } else if (endLayoutInfo.typeId === CommonConstants.TYPE_CARD) {
309          if (dragItemType === CommonConstants.DRAG_FROM_DOCK && deviceType == CommonConstants.DEFAULT_DEVICE_TYPE) {
310            localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_PAGEDESK_ITEM_ADD, dragItemInfo);
311            localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_RESIDENT_DOCK_ITEM_DELETE, dragItemInfo);
312            localEventManager.sendLocalEventSticky(EventConstants.EVENT_SMARTDOCK_INIT_FINISHED, null);
313            return true;
314          }
315        }
316      }
317    }
318
319    if (dragItemType === CommonConstants.DRAG_FROM_DOCK && deviceType == CommonConstants.DEFAULT_DEVICE_TYPE) {
320      let appInfoTemp = {
321        "bundleName": dragItemInfo.bundleName,
322        "typeId": dragItemInfo.typeId,
323        "abilityName": dragItemInfo.abilityName,
324        "moduleName": dragItemInfo.moduleName,
325        "keyName": dragItemInfo.keyName,
326        "area": dragItemInfo.area,
327        "page": dragItemInfo.page,
328        "column": this.getColumn(endIndex),
329        "row": this.getRow(endIndex)
330      };
331      layoutInfo.push(appInfoTemp);
332      localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_RESIDENT_DOCK_ITEM_DELETE, dragItemInfo);
333    } else {
334      this.checkAndMove(this.mStartPosition, this.mEndPosition, layoutInfo, dragItemInfo);
335    }
336
337    info.layoutInfo = layoutInfo;
338    this.mSettingsModel.setLayoutInfo(info);
339    localEventManager.sendLocalEventSticky(EventConstants.EVENT_SMARTDOCK_INIT_FINISHED, null);
340    this.deleteBlankPageAfterDragging(startPosition, endPosition);
341    return true;
342  }
343
344  private updateEndPosition(dragItemInfo: LauncherDragItemInfo): void {
345    this.mGridConfig = this.mSettingsModel.getGridConfig();
346    if (this.mEndPosition.row < 0) {
347      this.mEndPosition.row = 0;
348    } else if (this.mEndPosition.row + dragItemInfo.area[1] > this.mGridConfig.row) {
349      this.mEndPosition.row = this.mGridConfig.row - dragItemInfo.area[1];
350    }
351    if (this.mEndPosition.column < 0) {
352      this.mEndPosition.column = 0;
353    } else if (this.mEndPosition.column + dragItemInfo.area[0] > this.mGridConfig.column ) {
354      this.mEndPosition.column = this.mGridConfig.column - dragItemInfo.area[0];
355    }
356  }
357
358  deleteBlankPageOutsideEffect() {
359    // delete Blank Page because of drag outside effect area
360    Log.showInfo(TAG, "deleteBlankPageOutsideEffect" );
361    const startPosition: DragItemPosition = this.copyPosition(this.mStartPosition);
362    this.deleteBlankPageAfterDragging(startPosition, startPosition);
363  }
364
365  /**
366   * copy a new position object by original position
367   *
368   * @param position - original position
369   */
370  private copyPosition(position: DragItemPosition): DragItemPosition {
371    if (CheckEmptyUtils.isEmpty(position)) {
372      return null;
373    }
374    const directionPosition: DragItemPosition = {
375      page: position.page,
376      row: position.row,
377      column: position.column,
378      X: position.X,
379      Y: position.Y
380    };
381    return directionPosition;
382  }
383
384  /**
385   * delete blank page after dragging
386   *
387   * @param startPosition - drag start position
388   * @param endPosition - drag end position
389   */
390  deleteBlankPageAfterDragging(startPosition: DragItemPosition, endPosition: DragItemPosition): void {
391    const layoutInfo = this.mSettingsModel.getLayoutInfo();
392    const pageCount = layoutInfo.layoutDescription.pageCount;
393    const isAddByDraggingFlag = this.mPageDesktopModel.isAddByDragging();
394    let deleteLastFlag = false;
395    if (isAddByDraggingFlag && (CheckEmptyUtils.isEmpty(endPosition) ||
396    !CheckEmptyUtils.isEmpty(endPosition) && endPosition.page != pageCount - 1 )) {
397      layoutInfo.layoutDescription.pageCount = pageCount - 1;
398      deleteLastFlag = true;
399    }
400    let deleteStartFlag = false;
401    if (!CheckEmptyUtils.isEmpty(startPosition)) {
402      deleteStartFlag = this.mPageDesktopModel.deleteBlankPageFromLayoutInfo(layoutInfo, startPosition.page);
403    }
404    if (CheckEmptyUtils.isEmpty(endPosition) || JSON.stringify(startPosition) === JSON.stringify(endPosition)) {
405      Log.showDebug(TAG, `pageIndex: ${JSON.stringify(startPosition) === JSON.stringify(endPosition)}`);
406      AppStorage.setOrCreate('pageIndex', startPosition.page);
407    } else if (deleteStartFlag) {
408      if (startPosition.page > endPosition.page) {
409        AppStorage.setOrCreate('pageIndex', endPosition.page);
410      } else if (endPosition.page > startPosition.page &&
411      endPosition.page < layoutInfo.layoutDescription.pageCount) {
412        AppStorage.setOrCreate('pageIndex', endPosition.page - 1);
413      }
414    }
415    this.mPageDesktopModel.setAddByDragging(false);
416    if (deleteLastFlag || deleteStartFlag) {
417      this.mSettingsModel.setLayoutInfo(layoutInfo);
418      localEventManager.sendLocalEventSticky(EventConstants.EVENT_REQUEST_PAGEDESK_REFRESH, null);
419    }
420  }
421
422  private isMoveToSamePosition(dragItemInfo: LauncherDragItemInfo): boolean {
423    if (this.mEndPosition.page == dragItemInfo.page &&
424    this.mEndPosition.row == dragItemInfo.row && this.mEndPosition.column == dragItemInfo.column) {
425      return true;
426    }
427    return false;
428  }
429
430  private getEndLayoutInfo(layoutInfo) {
431    const endLayoutInfo = layoutInfo.find(item => {
432      if (item.typeId == CommonConstants.TYPE_FOLDER || item.typeId == CommonConstants.TYPE_CARD) {
433        return item.page === this.mEndPosition.page && this.isItemInRowColumn(this.mEndPosition.row, this.mEndPosition.column, item);
434      } else if (item.typeId == CommonConstants.TYPE_APP) {
435        return item.page === this.mEndPosition.page && item.row === this.mEndPosition.row && item.column === this.mEndPosition.column;
436      }
437    });
438    return endLayoutInfo;
439  }
440
441  private getStartLayoutInfo(layoutInfo, dragItemInfo: LauncherDragItemInfo): LauncherDragItemInfo {
442    const startLayoutInfo = layoutInfo.find(item => {
443      return item.page === dragItemInfo.page && item.row === dragItemInfo.row && item.column === dragItemInfo.column;
444    });
445    return startLayoutInfo;
446  }
447
448  /**
449   * folder squeeze handle
450   * @param source
451   * @param destination
452   * @param layoutInfo
453   * @param dragItemInfo
454   */
455  private checkAndMove(source, destination, layoutInfo, dragItemInfo: LauncherDragItemInfo): boolean {
456    Log.showDebug(TAG, 'checkAndMove start');
457
458    const allPositions = this.getAllPositions(destination, layoutInfo);
459    const objectPositionCount = this.getObjectPositionCount(destination, layoutInfo);
460    const pressedPositions = this.getPressedObjects(destination, allPositions, dragItemInfo);
461
462    // source and destination is in the same page
463    if (source.page == destination.page && !this.checkCanMoveInSamePage(pressedPositions, objectPositionCount, dragItemInfo)) {
464      return false;
465    }
466    // source and destination is in diff page
467    if (source.page != destination.page && !this.checkCanMoveInDiffPage(allPositions, dragItemInfo)) {
468      return false;
469    }
470
471    if (source.page == destination.page) {
472      this.setSourcePositionToNull(dragItemInfo, allPositions);
473    }
474    this.setDestinationPosition(destination, allPositions, dragItemInfo);
475
476    Log.showDebug(TAG, `checkAndMove pressedPositions.foldersAndForms: ${pressedPositions.foldersAndForms.length}`);
477    if (pressedPositions.foldersAndForms.length != 0) {
478      if (!this.moveFoldersAndForms(pressedPositions.foldersAndForms, destination, allPositions, dragItemInfo)) {
479        return false;
480      }
481    }
482    Log.showDebug(TAG, `checkAndMove pressedPositions.apps.length: ${pressedPositions.apps.length}`);
483    if (pressedPositions.apps.length != 0) {
484      this.moveApps(pressedPositions.apps, allPositions);
485    }
486    Log.showDebug(TAG, 'checkAndMove update destination ');
487    this.updateDestinationByDragItem(dragItemInfo, destination, allPositions);
488    Log.showDebug(TAG, 'checkAndMove update layoutInfo ');
489    for (let index = 0; index < layoutInfo.length; index++) {
490      for (let row = allPositions.length - 1; row >= 0 ; row--) {
491        for (let column = allPositions[row].length - 1; column >= 0 ; column--) {
492          if (layoutInfo[index].typeId == CommonConstants.TYPE_APP && layoutInfo[index].keyName == allPositions[row][column].keyName ||
493          layoutInfo[index].typeId == CommonConstants.TYPE_FOLDER && layoutInfo[index].folderId == allPositions[row][column].keyName ||
494          layoutInfo[index].typeId == CommonConstants.TYPE_CARD && layoutInfo[index].cardId == allPositions[row][column].keyName) {
495            layoutInfo[index].row = row;
496            layoutInfo[index].column = column;
497            layoutInfo[index].page = destination.page;
498          }
499        }
500      }
501    }
502    Log.showDebug(TAG, 'checkAndMove end');
503    return true;
504  }
505
506  /**
507   * get desktop's position info
508   * @param destination
509   * @param layoutInfo
510   */
511  private getAllPositions(destination, layoutInfo): any[] {
512    Log.showDebug(TAG, 'getAllPositions start');
513    const allPositions = [];
514    this.setAllpositionsToNull(allPositions);
515
516    // set position in layoutInfo to all positions
517    for (let i = 0; i < layoutInfo.length; i++) {
518      if (layoutInfo[i].page == destination.page) {
519        if (layoutInfo[i].typeId == CommonConstants.TYPE_FOLDER || layoutInfo[i].typeId == CommonConstants.TYPE_CARD) {
520          let keyName = '';
521          if (layoutInfo[i].typeId == CommonConstants.TYPE_FOLDER) {
522            keyName = layoutInfo[i].folderId;
523          } else if (layoutInfo[i].typeId == CommonConstants.TYPE_CARD) {
524            keyName = layoutInfo[i].cardId;
525          }
526
527          const positionInLayoutInfo = {
528            typeId: layoutInfo[i].typeId,
529            keyName: keyName,
530            area: layoutInfo[i].area
531          };
532          for (let k = 0; k < layoutInfo[i].area[1]; k++) {
533            for (let j = 0; j < layoutInfo[i].area[0]; j++) {
534              allPositions[layoutInfo[i].row + k][layoutInfo[i].column + j] = positionInLayoutInfo;
535            }
536          }
537        } else if (layoutInfo[i].typeId == CommonConstants.TYPE_APP) {
538          const positionInLayoutInfo = {
539            typeId: layoutInfo[i].typeId,
540            keyName: layoutInfo[i].keyName,
541            area: layoutInfo[i].area
542          };
543          allPositions[layoutInfo[i].row][layoutInfo[i].column] = positionInLayoutInfo;
544        }
545      }
546    }
547    return allPositions;
548  }
549
550  private setAllpositionsToNull(allPositions): void {
551    const mGridConfig = this.mSettingsModel.getGridConfig();
552    const pageRow = mGridConfig.row;
553    const pageColumn = mGridConfig.column;
554
555    // set null to all positions in current page
556    for (let row = 0; row < pageRow; row++) {
557      const rowPositions = [];
558      for (let column = 0; column < pageColumn; column++) {
559        const position = {
560          typeId: -1,
561          keyName: 'null',
562          area: []
563        };
564        rowPositions.push(position);
565      }
566      allPositions.push(rowPositions);
567    }
568  }
569
570  /**
571   * get desktop's position count by Object
572   * @param destination
573   * @param layoutInfo
574   */
575  private getObjectPositionCount(destination, layoutInfo): Map<string, number> {
576    Log.showDebug(TAG, 'getObjectPositionCount start');
577
578    const objectPositionCount = new Map<string, number>();
579    // set position in layoutInfo to all positions
580    for (let i = 0; i < layoutInfo.length; i++) {
581      if (layoutInfo[i].page == destination.page) {
582        const count = layoutInfo[i].area[0] * layoutInfo[i].area[1];
583        let keyName = '';
584        if (layoutInfo[i].typeId == CommonConstants.TYPE_FOLDER) {
585          keyName = layoutInfo[i].folderId;
586        } else if (layoutInfo[i].typeId == CommonConstants.TYPE_CARD) {
587          keyName = layoutInfo[i].cardId;
588        } else if (layoutInfo[i].typeId == CommonConstants.TYPE_APP) {
589          keyName = layoutInfo[i].keyName;
590        }
591        objectPositionCount.set(keyName, count);
592      }
593    }
594    return objectPositionCount;
595  }
596
597  /**
598   * get Object under pressed big folder or form
599   * @param destination
600   * @param allPositions
601   * @param dragItemInfo
602   */
603  private getPressedObjects(destination, allPositions, dragItemInfo: LauncherDragItemInfo): {
604    apps: Array<LauncherDragItemInfo>,
605    foldersAndForms: Array<LauncherDragItemInfo>
606  } {
607    Log.showDebug(TAG, 'getPressedObjects start');
608    const row = destination.row;
609    const column = destination.column;
610    const apps = [];
611    const foldersAndForms = [];
612
613    Log.showDebug(TAG, `getPressedObjects destination.row: ${row},destination.column:${column}`);
614
615    for (let j = 0; j < dragItemInfo.area[1]; j++) {
616      for (let i = 0; i < dragItemInfo.area[0]; i++) {
617        if (allPositions[row + j][column + i].typeId == CommonConstants.TYPE_APP) {
618          apps.push(allPositions[row + j][column + i]);
619        } else if (allPositions[row + j][column + i].typeId == CommonConstants.TYPE_FOLDER &&
620        allPositions[row + j][column + i].keyName != dragItemInfo.folderId) {
621          foldersAndForms.push(allPositions[row + j][column + i]);
622        } else if (allPositions[row + j][column + i].typeId == CommonConstants.TYPE_CARD &&
623        allPositions[row + j][column + i].keyName != dragItemInfo.cardId) {
624          foldersAndForms.push(allPositions[row + j][column + i]);
625        }
626      }
627    }
628
629    Log.showDebug(TAG, `getPressedObjects foldersAndForms.length: ${foldersAndForms.length}`);
630    Log.showDebug(TAG, `getPressedObjects apps.length: ${apps.length}`);
631    const pressedObjects = {
632      apps,
633      foldersAndForms
634    };
635    return pressedObjects;
636  }
637
638  /**
639   * check of canMove in same page
640   * @param pressedPositions
641   * @param objectPositionCount
642   * @param dragItemInfo
643   */
644  private checkCanMoveInSamePage(pressedPositions, objectPositionCount, dragItemInfo: LauncherDragItemInfo): boolean {
645    Log.showDebug(TAG, 'checkCanMoveInSamePage start');
646    const foldersAndForms = pressedPositions.foldersAndForms;
647    if (foldersAndForms.length == 0) {
648      return true;
649    }
650
651    if (foldersAndForms.length == 1) {
652      if (dragItemInfo.typeId == CommonConstants.TYPE_APP && foldersAndForms[0].typeId == CommonConstants.TYPE_CARD) {
653        return true;
654      }
655    }
656
657    const coverPositionCount = new Map<string, number>();
658    Log.showDebug(TAG, `checkCanMoveInSamePage foldersAndForms.length: ${foldersAndForms.length}`);
659    for (let i = 0; i < foldersAndForms.length; i++) {
660      const keyName = foldersAndForms[i].keyName;
661      if (coverPositionCount.has(keyName)) {
662        coverPositionCount.set(keyName, coverPositionCount.get(keyName) + 1);
663      } else {
664        coverPositionCount.set(keyName, 1);
665      }
666    }
667
668    for (const keyName of coverPositionCount.keys()) {
669      if (coverPositionCount.get(keyName) < objectPositionCount.get(keyName) / 2) {
670        Log.showDebug(TAG, 'checkCanMoveInSamePage end false');
671        return false;
672      }
673    }
674    return true;
675  }
676
677  /**
678   * check of canMove in diff page
679   * @param allPositions
680   */
681  private checkCanMoveInDiffPage(allPositions, dragItemInfo): boolean {
682    Log.showDebug(TAG, 'checkCanMoveInDiffPage start');
683    let count = 0;
684    for (let i = 0; i < allPositions.length; i++) {
685      for (let j = 0; j < allPositions[i].length; j++) {
686        if (allPositions[i][j].typeId == -1) {
687          count++;
688        }
689      }
690    }
691    const minCount = dragItemInfo.area[0] * dragItemInfo.area[1];
692    // target page empty position min is dragItemInfo's need position
693    if (count < minCount) {
694      Log.showDebug(TAG, 'checkCanMoveInDiffPage end false');
695      return false;
696    }
697    return true;
698  }
699
700  /**
701   * set source‘s position to null
702   * @param source
703   * @param allPositions
704   */
705  private setSourcePositionToNull(dragItemInfo, allPositions): void {
706    Log.showDebug(TAG, 'setSourcePositionToNull start');
707    for (let j = 0; j < dragItemInfo.area[1]; j++) {
708      for (let i = 0; i < dragItemInfo.area[0]; i++) {
709        const nullPosition = {
710          typeId: -1,
711          keyName: 'null',
712          area: []
713        };
714        allPositions[dragItemInfo.row + j][dragItemInfo.column + i] = nullPosition;
715      }
716    }
717  }
718
719  /**
720   * set direction‘s position to null
721   * @param destination
722   * @param allPositions
723   * @param dragItemInfo
724   */
725  private setDestinationPosition(destination, allPositions, dragItemInfo): void {
726    Log.showDebug(TAG, 'setDestinationPosition start');
727    let keyName = '';
728    if (dragItemInfo.typeId == CommonConstants.TYPE_FOLDER) {
729      keyName = dragItemInfo.folderId;
730    } else if (dragItemInfo.typeId == CommonConstants.TYPE_CARD) {
731      keyName = dragItemInfo.cardId;
732    } else if (dragItemInfo.typeId == CommonConstants.TYPE_APP) {
733      keyName = dragItemInfo.keyName;
734    }
735
736    for (let j = 0; j < dragItemInfo.area[1]; j++) {
737      for (let i = 0; i < dragItemInfo.area[0]; i++) {
738        if (allPositions[destination.row + j][destination.column+ i].typeId == -1) {
739          const destinationPosition = {
740            typeId: dragItemInfo.typeId,
741            keyName: keyName,
742            area: dragItemInfo.area
743          };
744          allPositions[destination.row + j][destination.column+ i] = destinationPosition;
745        }
746      }
747    }
748  }
749
750  /**
751   * move folders and forms to target position
752   * @param foldersAndForms
753   * @param destination
754   * @param allPositions
755   * @param dragItemInfo
756   */
757  private moveFoldersAndForms(foldersAndForms, destination, allPositions, dragItemInfo: LauncherDragItemInfo): boolean {
758    Log.showDebug(TAG, 'moveFoldersAndForms start');
759    const movedFoldersAndForms = [];
760    for (let i = 0; i < foldersAndForms.length; i++) {
761      const moveFolderOrForm = foldersAndForms[i];
762      if (movedFoldersAndForms.indexOf(moveFolderOrForm.keyName) != -1) {
763        continue;
764      }
765
766      for (let row = 0; row < allPositions.length; row++) {
767        for (let column = 0; column < allPositions[row].length; column++) {
768          if (moveFolderOrForm.keyName == allPositions[row][column].keyName) {
769            this.updateDestinationToNull(dragItemInfo, destination, allPositions, row, column);
770          }
771        }
772      }
773
774      let isUsablePosition = false;
775      for (let row = 0; row < allPositions.length; row++) {
776        if (isUsablePosition) {
777          break;
778        }
779        for (let column = 0; column < allPositions[row].length; column++) {
780          const usablePositionCount =this.getUsablePositionCount(moveFolderOrForm, allPositions, row , column);
781          if (usablePositionCount == moveFolderOrForm.area[1] * moveFolderOrForm.area[0]) {
782            isUsablePosition = true;
783            this.updatePositionByMoveItem(moveFolderOrForm, allPositions, row, column);
784            movedFoldersAndForms.push(moveFolderOrForm.keyName);
785            break;
786          }
787        }
788      }
789      if (!isUsablePosition) {
790        Log.showDebug(TAG, 'moveFoldersAndForms return false');
791        return false;
792      }
793    }
794    this.updateDestinationByDragItem(dragItemInfo, destination, allPositions);
795    return true;
796  }
797
798  /**
799   * get the count of usable position
800   * @param moveFolderOrForm
801   * @param allPositions
802   * @param row
803   * @param column
804   */
805  private getUsablePositionCount(moveFolderOrForm, allPositions, row , column): number {
806    let getUsablePositionCount = 0;
807    for (let j = 0; j < moveFolderOrForm.area[1]; j++) {
808      for (let i = 0; i < moveFolderOrForm.area[0]; i++) {
809        if (row + j < allPositions.length && column + i < allPositions[row].length && allPositions[row + j][column + i].typeId == -1) {
810          getUsablePositionCount++;
811        }
812      }
813    }
814    return getUsablePositionCount;
815  }
816
817  /**
818   * update destination to nullPosition
819   *
820   * @param dragItemInfo
821   * @param destination
822   * @param allPositions
823   * @param row
824   * @param column
825   */
826  private updateDestinationToNull(dragItemInfo: LauncherDragItemInfo, destination, allPositions, row, column): void {
827    let destinationFlag = false;
828    for (let j = 0; j < dragItemInfo.area[1]; j++) {
829      if (destinationFlag) {
830        break;
831      }
832      for (let i = 0; i < dragItemInfo.area[0]; i++) {
833        if (destination.row + j == row && destination.column + i == column) {
834          destinationFlag = true;
835          break;
836        }
837      }
838    }
839    if (!destinationFlag) {
840      const nullPosition = {
841        typeId: -1,
842        keyName: 'null',
843        area: []
844      };
845      allPositions[row][column] = nullPosition;
846    }
847  }
848
849  /**
850   * update destination position by dragItemInfo
851   *
852   * @param dragItemInfo
853   * @param destination
854   * @param allPositions
855   */
856  private updateDestinationByDragItem(dragItemInfo: LauncherDragItemInfo, destination, allPositions): void {
857    let keyName = '';
858    if (dragItemInfo.typeId == CommonConstants.TYPE_FOLDER) {
859      keyName = dragItemInfo.folderId;
860    } else if (dragItemInfo.typeId == CommonConstants.TYPE_CARD) {
861      keyName = dragItemInfo.cardId >= 0 ? String(dragItemInfo.cardId) : '';
862    } else if (dragItemInfo.typeId == CommonConstants.TYPE_APP) {
863      keyName = dragItemInfo.keyName;
864    }
865
866    for (let j = 0; j < dragItemInfo.area[1]; j++) {
867      for (let i = 0; i < dragItemInfo.area[0]; i++) {
868        const dragItemPosition = {
869          typeId: dragItemInfo.typeId,
870          keyName: keyName,
871          area: dragItemInfo.area
872        };
873        allPositions[destination.row + j][destination.column + i] = dragItemPosition;
874      }
875    }
876  }
877
878  /**
879   * update positions by moveItemInfo
880   *
881   * @param moveFolderOrForm
882   * @param allPositions
883   * @param row
884   * @param column
885   */
886  private updatePositionByMoveItem(moveFolderOrForm, allPositions, row, column): void {
887    for (let j = 0; j < moveFolderOrForm.area[1]; j++) {
888      for (let i = 0; i < moveFolderOrForm.area[0]; i++) {
889        const movePosition = {
890          typeId: moveFolderOrForm.typeId,
891          keyName: moveFolderOrForm.keyName,
892          area: moveFolderOrForm.area
893        };
894        allPositions[row + j][column + i] = movePosition;
895      }
896    }
897  }
898
899  /**
900   * move apps to target position
901   * @param apps
902   * @param allPositions
903   */
904  private moveApps(apps, allPositions): void {
905    Log.showDebug(TAG, 'moveApps start');
906    for (let i = 0; i < apps.length; i++) {
907      const app = apps[i];
908      let isUsable = false;
909      for (let row = 0; row < allPositions.length; row++) {
910        if (isUsable) {
911          break;
912        }
913        for (let column = 0; column < allPositions[row].length; column++) {
914          if (allPositions[row][column].typeId == -1) {
915            const appPosition = {
916              typeId: app.typeId,
917              keyName: app.keyName,
918              area: app.area
919            };
920            allPositions[row][column] = appPosition;
921            isUsable = true;
922            break;
923          }
924        }
925      }
926    }
927  }
928}
929