@@ -26,6 +26,7 @@ import android.view.animation.OvershootInterpolator
2626import android.widget.RelativeLayout
2727import androidx.core.graphics.drawable.toBitmap
2828import androidx.core.graphics.drawable.toDrawable
29+ import androidx.core.graphics.toRect
2930import androidx.core.graphics.withScale
3031import androidx.core.graphics.withTranslation
3132import androidx.core.view.ViewCompat
@@ -42,6 +43,7 @@ import com.simplemobiletools.launcher.extensions.getDrawableForPackageName
4243import com.simplemobiletools.launcher.extensions.homeScreenGridItemsDB
4344import com.simplemobiletools.launcher.helpers.*
4445import com.simplemobiletools.launcher.models.HomeScreenGridItem
46+ import kotlinx.collections.immutable.toImmutableList
4547import kotlin.math.*
4648
4749class HomeScreenGrid (context : Context , attrs : AttributeSet , defStyle : Int ) : RelativeLayout(context, attrs, defStyle) {
@@ -87,6 +89,7 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
8789 pageChangeStarted = {
8890 widgetViews.forEach { it.resetTouches() }
8991 closeFolder()
92+ accessibilityHelper.invalidateRoot()
9093 }
9194 )
9295
@@ -105,12 +108,13 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
105108 val appWidgetHost = MyAppWidgetHost (context, WIDGET_HOST_ID )
106109 private val appWidgetManager = AppWidgetManager .getInstance(context)
107110
111+ private val accessibilityHelper = HomeScreenGridTouchHelper (this )
108112 var itemClickListener: ((HomeScreenGridItem ) -> Unit )? = null
109113 var itemLongClickListener: ((HomeScreenGridItem ) -> Unit )? = null
110114
111115
112116 init {
113- ViewCompat .setAccessibilityDelegate(this , HomeScreenGridTouchHelper ( this ) )
117+ ViewCompat .setAccessibilityDelegate(this , accessibilityHelper )
114118
115119 textPaint = TextPaint (Paint .ANTI_ALIAS_FLAG ).apply {
116120 color = Color .WHITE
@@ -179,7 +183,7 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
179183 ensureBackgroundThread {
180184 val providers = appWidgetManager.installedProviders
181185 gridItems = context.homeScreenGridItemsDB.getAllItems() as ArrayList <HomeScreenGridItem >
182- gridItems.forEach { item ->
186+ gridItems.toImmutableList(). forEach { item ->
183187 if (item.type == ITEM_TYPE_ICON ) {
184188 item.drawable = context.getDrawableForPackageName(item.packageName)
185189 } else if (item.type == ITEM_TYPE_FOLDER ) {
@@ -241,6 +245,13 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
241245 ensureBackgroundThread {
242246 if (item.id != null ) {
243247 context.homeScreenGridItemsDB.deleteById(item.id!! )
248+ if (item.parentId != null ) {
249+ gridItems.filter { it.parentId == item.parentId && it.left > item.left && it.id != item.id }.forEach {
250+ it.left - = 1
251+ }
252+
253+ context.homeScreenGridItemsDB.shiftFolderItems(item.parentId!! , item.left, - 1 , item.id)
254+ }
244255 }
245256
246257 if (item.type == ITEM_TYPE_WIDGET ) {
@@ -682,9 +693,20 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
682693 draggedItem!! .activityInfo
683694 )
684695
696+ fun finalizeFolderOrder (newItem : HomeScreenGridItem ) {
697+ if (newParentId != null && gridItems.any { it.parentId == newParentId && it.left == newItem.left }) {
698+ gridItems.filter { it.parentId == newParentId && it.left >= newItem.left && it.id != newItem.id}.forEach {
699+ it.left + = 1
700+ }
701+
702+ context.homeScreenGridItemsDB.shiftFolderItems(newParentId, newItem.left - 1 , + 1 , newItem.id)
703+ }
704+ }
705+
685706 if (newHomeScreenGridItem.type == ITEM_TYPE_ICON ) {
686707 ensureBackgroundThread {
687708 storeAndShowGridItem(newHomeScreenGridItem)
709+ finalizeFolderOrder(newHomeScreenGridItem)
688710 }
689711 } else if (newHomeScreenGridItem.type == ITEM_TYPE_SHORTCUT ) {
690712 (context as ? MainActivity )?.handleShorcutCreation(newHomeScreenGridItem.activityInfo!! ) { shortcutId, label, icon ->
@@ -694,19 +716,10 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
694716 newHomeScreenGridItem.icon = icon.toBitmap()
695717 newHomeScreenGridItem.drawable = icon
696718 storeAndShowGridItem(newHomeScreenGridItem)
719+ finalizeFolderOrder(newHomeScreenGridItem)
697720 }
698721 }
699722 }
700-
701- ensureBackgroundThread {
702- if (newParentId != null && gridItems.any { it.parentId == newParentId && it.left == finalXIndex }) {
703- gridItems.filter { it.parentId == newParentId && it.left >= finalXIndex }.forEach {
704- it.left + = 1
705- }
706-
707- context.homeScreenGridItemsDB.shiftFolderItems(newParentId, left - 1 , + 1 )
708- }
709- }
710723 }
711724
712725 draggedItem = null
@@ -1052,7 +1065,6 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
10521065
10531066 items.forEach { item ->
10541067 val itemRect = folder.getItemRect(item)
1055- // canvas.drawRect(itemRect, contrastTextPaint)
10561068 canvas.drawItemInCell(item, itemRect)
10571069 }
10581070 }
@@ -1098,8 +1110,9 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
10981110 // show the app icon itself at dragging, move it above the finger a bit to make it visible
10991111 val drawableX = (draggedItemCurrentCoords.first - iconSize / 1.5f ).toInt()
11001112 val drawableY = (draggedItemCurrentCoords.second - iconSize / 1.2f ).toInt()
1101- draggedItem!! .drawable!! .setBounds(drawableX, drawableY, drawableX + iconSize, drawableY + iconSize)
1102- draggedItem!! .drawable!! .draw(canvas)
1113+ val newDrawable = draggedItem!! .drawable?.constantState?.newDrawable()?.mutate()
1114+ newDrawable?.setBounds(drawableX, drawableY, drawableX + iconSize, drawableY + iconSize)
1115+ newDrawable?.draw(canvas)
11031116 } else if (draggedItem!! .type == ITEM_TYPE_WIDGET ) {
11041117 // at first draw we are loading the widget from the database at some exact spot, not dragging it
11051118 if (! isFirstDraw) {
@@ -1119,18 +1132,19 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
11191132 }
11201133
11211134 // show the widget preview itself at dragging
1122- val drawable = draggedItem!! .drawable!!
1123- val aspectRatio = drawable.minimumHeight / drawable.minimumWidth.toFloat()
1124- val drawableX = (draggedItemCurrentCoords.first - drawable.minimumWidth / 2f ).toInt()
1125- val drawableY = (draggedItemCurrentCoords.second - drawable.minimumHeight / 3f ).toInt()
1126- val drawableWidth = draggedItem!! .getWidthInCells() * cellWidth - iconMargin * (draggedItem!! .getWidthInCells() - 1 )
1127- drawable.setBounds(
1128- drawableX,
1129- drawableY,
1130- drawableX + drawableWidth,
1131- (drawableY + drawableWidth * aspectRatio).toInt()
1132- )
1133- drawable.draw(canvas)
1135+ draggedItem!! .drawable?.also { drawable ->
1136+ val aspectRatio = drawable.minimumHeight / drawable.minimumWidth.toFloat()
1137+ val drawableX = (draggedItemCurrentCoords.first - drawable.minimumWidth / 2f ).toInt()
1138+ val drawableY = (draggedItemCurrentCoords.second - drawable.minimumHeight / 3f ).toInt()
1139+ val drawableWidth = draggedItem!! .getWidthInCells() * cellWidth - iconMargin * (draggedItem!! .getWidthInCells() - 1 )
1140+ drawable.setBounds(
1141+ drawableX,
1142+ drawableY,
1143+ drawableX + drawableWidth,
1144+ (drawableY + drawableWidth * aspectRatio).toInt()
1145+ )
1146+ drawable.draw(canvas)
1147+ }
11341148 }
11351149 }
11361150 }
@@ -1299,23 +1313,53 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
12991313 }
13001314
13011315 override fun getVisibleVirtualViews (virtualViewIds : MutableList <Int >? ) {
1302- val sorted = gridItems.sortedBy {
1303- it.getDockAdjustedTop(rowCount) * 100 + it.left
1316+ val sorted = gridItems.filter { it.visibleOnCurrentPage() || (currentlyOpenFolder != null && it.parentId == currentlyOpenFolder?.item?.id) }. sortedBy {
1317+ ( if ( it.parentId == null ) it. getDockAdjustedTop(rowCount) else 1 ) * 100 + it.left
13041318 }
13051319 sorted.forEachIndexed { index, homeScreenGridItem ->
13061320 virtualViewIds?.add(index, homeScreenGridItem.id?.toInt() ? : index)
13071321 }
13081322 }
13091323
13101324 override fun onPopulateNodeForVirtualView (virtualViewId : Int , node : AccessibilityNodeInfoCompat ) {
1325+ val viewLocation = IntArray (2 )
1326+ getLocationOnScreen(viewLocation)
1327+
1328+ // home screen
1329+ if (virtualViewId == - 1 ) {
1330+ node.text = context.getString(R .string.app_name)
1331+ val viewBounds = Rect (left, top, right, bottom)
1332+ val onScreenBounds = Rect (viewBounds)
1333+ onScreenBounds.offset(viewLocation[0 ], viewLocation[1 ])
1334+ node.setBoundsInScreen(onScreenBounds)
1335+ node.setBoundsInParent(viewBounds)
1336+
1337+ node.addAction(AccessibilityNodeInfoCompat .ACTION_CLICK )
1338+ node.addAction(AccessibilityNodeInfoCompat .ACTION_LONG_CLICK )
1339+ node.setParent(this @HomeScreenGrid)
1340+ }
1341+
13111342 val item = gridItems.firstOrNull { it.id?.toInt() == virtualViewId } ? : throw IllegalArgumentException (" Unknown id" )
13121343
1313- node.text = item.title
1344+ node.text = if (item.type == ITEM_TYPE_WIDGET ) {
1345+ item.providerInfo?.loadLabel(context.packageManager) ? : item.title
1346+ } else {
1347+ item.title
1348+ }
13141349
1315- val viewLocation = IntArray (2 )
1316- getLocationOnScreen(viewLocation)
1350+ val viewBounds = if (item == currentlyOpenFolder?.item) {
1351+ currentlyOpenFolder?.getDrawingRect()?.toRect()
1352+ } else if (item.type == ITEM_TYPE_WIDGET ) {
1353+ val widgetPos = calculateWidgetPos(item.getTopLeft())
1354+ val left = widgetPos.x
1355+ val top = widgetPos.y
1356+ val right = left + item.getWidthInCells() * cellWidth
1357+ val bottom = top + item.getHeightInCells() * cellHeight
13171358
1318- val viewBounds = getClickableRect(item)
1359+ Rect (left, top, right, bottom)
1360+ } else {
1361+ getClickableRect(item)
1362+ }
13191363 val onScreenBounds = Rect (viewBounds)
13201364 onScreenBounds.offset(viewLocation[0 ], viewLocation[1 ])
13211365 node.setBoundsInScreen(onScreenBounds)
@@ -1330,7 +1374,11 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
13301374 val item = gridItems.firstOrNull { it.id?.toInt() == virtualViewId } ? : throw IllegalArgumentException (" Unknown id" )
13311375 when (action) {
13321376 AccessibilityNodeInfoCompat .ACTION_CLICK -> itemClickListener?.apply {
1333- invoke(item)
1377+ if (item == currentlyOpenFolder?.item) {
1378+ closeFolder(true )
1379+ } else {
1380+ invoke(item)
1381+ }
13341382 return true
13351383 }
13361384
@@ -1391,6 +1439,7 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
13911439 } else if (currentlyOpenFolder?.item?.id != folder.id) {
13921440 closeFolder()
13931441 }
1442+ accessibilityHelper.invalidateRoot()
13941443 }
13951444
13961445 fun closeFolder (redraw : Boolean = false) {
@@ -1399,6 +1448,7 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
13991448 if (redraw) {
14001449 redrawGrid()
14011450 }
1451+ accessibilityHelper.invalidateRoot()
14021452 }
14031453 }
14041454
@@ -1409,7 +1459,7 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
14091459 val drawable = if (item.type == ITEM_TYPE_FOLDER ) {
14101460 item.toFolder().generateDrawable()
14111461 } else {
1412- item.drawable!!
1462+ item.drawable?.constantState?.newDrawable()?.mutate()
14131463 }
14141464
14151465 if (item.docked) {
@@ -1458,7 +1508,7 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
14581508
14591509 private fun HomeScreenGridItem.visibleOnCurrentPage () = (pager.isItemOnCurrentPage(this ) || docked) && parentId == null
14601510
1461- private fun HomeScreenGridItem.isSingleCellType () = (drawable != null && type == ITEM_TYPE_ICON || type == ITEM_TYPE_SHORTCUT || type == ITEM_TYPE_FOLDER )
1511+ private fun HomeScreenGridItem.isSingleCellType () = (type == ITEM_TYPE_ICON || type == ITEM_TYPE_SHORTCUT || type == ITEM_TYPE_FOLDER )
14621512
14631513 private fun HomeScreenGridItem.toFolder (animateOpening : Boolean = false) = HomeScreenFolder (this , animateOpening)
14641514
@@ -1502,13 +1552,18 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
15021552 return null
15031553 }
15041554
1555+ val items = getItems()
1556+ val itemsCount = getItems().count()
1557+
1558+ if (itemsCount == 0 ) {
1559+ return null
1560+ }
1561+
15051562 val bitmap = Bitmap .createBitmap(iconSize, iconSize, Bitmap .Config .ARGB_8888 )
15061563 val canvas = Canvas (bitmap)
15071564 val circlePath = Path ().apply { addCircle((iconSize / 2 ).toFloat(), (iconSize / 2 ).toFloat(), (iconSize / 2 ).toFloat(), Path .Direction .CCW ) }
15081565 canvas.clipPath(circlePath)
15091566 canvas.drawPaint(folderIconBackgroundPaint)
1510- val items = getItems()
1511- val itemsCount = getItems().count()
15121567 val folderColumnCount = ceil(sqrt(itemsCount.toDouble())).roundToInt()
15131568 val folderRowCount = ceil(itemsCount.toFloat() / folderColumnCount).roundToInt()
15141569 val scaledCellSize = (iconSize.toFloat() / folderColumnCount)
@@ -1519,8 +1574,9 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
15191574 val (row, column) = getItemPosition(it)
15201575 val drawableX = (scaledGap + column * scaledIconSize + column * scaledGap).toInt()
15211576 val drawableY = (extraYMargin + scaledGap + row * scaledIconSize + row * scaledGap).toInt()
1522- it.drawable?.setBounds(drawableX, drawableY, drawableX + scaledIconSize.toInt(), drawableY + scaledIconSize.toInt())
1523- it.drawable?.draw(canvas)
1577+ val newDrawable = it.drawable?.constantState?.newDrawable()?.mutate()
1578+ newDrawable?.setBounds(drawableX, drawableY, drawableX + scaledIconSize.toInt(), drawableY + scaledIconSize.toInt())
1579+ newDrawable?.draw(canvas)
15241580 }
15251581 canvas.drawPath(circlePath, folderIconBorderPaint)
15261582 return BitmapDrawable (resources, bitmap)
@@ -1572,6 +1628,10 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel
15721628
15731629 fun getItemsGridCenters (): List <Triple <Int , Int , Int >> {
15741630 val count = getItems().count()
1631+ if (count == 0 ) {
1632+ return emptyList()
1633+ }
1634+
15751635 val columnsCount = ceil(sqrt(count.toDouble())).roundToInt()
15761636 val rowsCount = ceil(count.toFloat() / columnsCount).roundToInt()
15771637 val folderItemsRect = getItemsDrawingRect()
0 commit comments