mirror of
				https://github.com/SimpleMobileTools/Simple-Launcher.git
				synced 2025-06-05 21:59:15 +02:00 
			
		
		
		
	Merge pull request #84 from esensar/fix/home-screen-accessibility
Implement accessibility for HomeScreenGrid
This commit is contained in:
		| @@ -23,6 +23,7 @@ import android.os.Handler | ||||
| import android.provider.Telephony | ||||
| import android.telecom.TelecomManager | ||||
| import android.view.* | ||||
| import android.view.accessibility.AccessibilityNodeInfo | ||||
| import android.view.animation.DecelerateInterpolator | ||||
| import android.widget.PopupMenu | ||||
| import androidx.core.graphics.drawable.toBitmap | ||||
| @@ -139,6 +140,14 @@ class MainActivity : SimpleActivity(), FlingListener { | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         home_screen_grid.itemClickListener = { | ||||
|             performItemClick(it) | ||||
|         } | ||||
|  | ||||
|         home_screen_grid.itemLongClickListener = { | ||||
|             performItemLongClick(home_screen_grid.getClickableRect(it).left.toFloat(), it) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private fun findFirstEmptyCell(): Rect? { | ||||
| @@ -241,6 +250,7 @@ class MainActivity : SimpleActivity(), FlingListener { | ||||
|                     refetchLaunchers() | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             REQUEST_ALLOW_BINDING_WIDGET -> mActionOnCanBindWidget?.invoke(resultCode == Activity.RESULT_OK) | ||||
|             REQUEST_CONFIGURE_WIDGET -> mActionOnWidgetConfiguredWidget?.invoke(resultCode == Activity.RESULT_OK) | ||||
|             REQUEST_CREATE_SHORTCUT -> { | ||||
| @@ -403,6 +413,7 @@ class MainActivity : SimpleActivity(), FlingListener { | ||||
|         window.navigationBarColor = resources.getColor(R.color.semitransparent_navigation) | ||||
|         home_screen_grid.fragmentExpanded() | ||||
|         home_screen_grid.hideResizeLines() | ||||
|         fragment.performAccessibilityAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null) | ||||
|     } | ||||
|  | ||||
|     private fun hideFragment(fragment: View) { | ||||
| @@ -433,12 +444,7 @@ class MainActivity : SimpleActivity(), FlingListener { | ||||
|         mIgnoreMoveEvents = true | ||||
|         val clickedGridItem = home_screen_grid.isClickingGridItem(x.toInt(), y.toInt()) | ||||
|         if (clickedGridItem != null) { | ||||
|             if (clickedGridItem.type == ITEM_TYPE_ICON || clickedGridItem.type == ITEM_TYPE_SHORTCUT) { | ||||
|                 main_holder.performHapticFeedback() | ||||
|             } | ||||
|  | ||||
|             val anchorY = home_screen_grid.sideMargins.top + (clickedGridItem.top * home_screen_grid.cellHeight.toFloat()) | ||||
|             showHomeIconMenu(x, anchorY, clickedGridItem, false) | ||||
|             performItemLongClick(x, clickedGridItem) | ||||
|             return | ||||
|         } | ||||
|  | ||||
| @@ -450,24 +456,37 @@ class MainActivity : SimpleActivity(), FlingListener { | ||||
|         home_screen_grid.hideResizeLines() | ||||
|         val clickedGridItem = home_screen_grid.isClickingGridItem(x.toInt(), y.toInt()) | ||||
|         if (clickedGridItem != null) { | ||||
|             if (clickedGridItem.type == ITEM_TYPE_ICON) { | ||||
|                 launchApp(clickedGridItem.packageName, clickedGridItem.activityName) | ||||
|             } else if (clickedGridItem.type == ITEM_TYPE_SHORTCUT) { | ||||
|                 if (clickedGridItem.intent.isNotEmpty()) { | ||||
|                     launchShortcutIntent(clickedGridItem) | ||||
|                 } else { | ||||
|                     // launch pinned shortcuts | ||||
|                     val id = clickedGridItem.shortcutId | ||||
|                     val packageName = clickedGridItem.packageName | ||||
|                     val userHandle = android.os.Process.myUserHandle() | ||||
|                     val shortcutBounds = home_screen_grid.getClickableRect(clickedGridItem) | ||||
|                     val launcherApps = applicationContext.getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps | ||||
|                     launcherApps.startShortcut(packageName, id, shortcutBounds, null, userHandle) | ||||
|                 } | ||||
|             performItemClick(clickedGridItem) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private fun performItemClick(clickedGridItem: HomeScreenGridItem) { | ||||
|         if (clickedGridItem.type == ITEM_TYPE_ICON) { | ||||
|             launchApp(clickedGridItem.packageName, clickedGridItem.activityName) | ||||
|         } else if (clickedGridItem.type == ITEM_TYPE_SHORTCUT) { | ||||
|             if (clickedGridItem.intent.isNotEmpty()) { | ||||
|                 launchShortcutIntent(clickedGridItem) | ||||
|             } else { | ||||
|                 // launch pinned shortcuts | ||||
|                 val id = clickedGridItem.shortcutId | ||||
|                 val packageName = clickedGridItem.packageName | ||||
|                 val userHandle = android.os.Process.myUserHandle() | ||||
|                 val shortcutBounds = home_screen_grid.getClickableRect(clickedGridItem) | ||||
|                 val launcherApps = applicationContext.getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps | ||||
|                 launcherApps.startShortcut(packageName, id, shortcutBounds, null, userHandle) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private fun performItemLongClick(x: Float, clickedGridItem: HomeScreenGridItem) { | ||||
|         if (clickedGridItem.type == ITEM_TYPE_ICON || clickedGridItem.type == ITEM_TYPE_SHORTCUT) { | ||||
|             main_holder.performHapticFeedback() | ||||
|         } | ||||
|  | ||||
|         val anchorY = home_screen_grid.sideMargins.top + (clickedGridItem.top * home_screen_grid.cellHeight.toFloat()) | ||||
|         showHomeIconMenu(x, anchorY, clickedGridItem, false) | ||||
|     } | ||||
|  | ||||
|     fun showHomeIconMenu(x: Float, y: Float, gridItem: HomeScreenGridItem, isOnAllAppsFragment: Boolean) { | ||||
|         home_screen_grid.hideResizeLines() | ||||
|         mLongPressedIcon = gridItem | ||||
|   | ||||
| @@ -15,8 +15,12 @@ import android.text.TextUtils | ||||
| import android.util.AttributeSet | ||||
| import android.util.Size | ||||
| import android.util.SizeF | ||||
| import android.view.View | ||||
| import android.widget.RelativeLayout | ||||
| import androidx.core.graphics.drawable.toDrawable | ||||
| import androidx.core.view.ViewCompat | ||||
| import androidx.core.view.accessibility.AccessibilityNodeInfoCompat | ||||
| import androidx.customview.widget.ExploreByTouchHelper | ||||
| import com.simplemobiletools.commons.extensions.* | ||||
| import com.simplemobiletools.commons.helpers.ensureBackgroundThread | ||||
| import com.simplemobiletools.commons.helpers.isSPlus | ||||
| @@ -58,7 +62,12 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel | ||||
|     val appWidgetHost = MyAppWidgetHost(context, WIDGET_HOST_ID) | ||||
|     private val appWidgetManager = AppWidgetManager.getInstance(context) | ||||
|  | ||||
|     var itemClickListener: ((HomeScreenGridItem) -> Unit)? = null | ||||
|     var itemLongClickListener: ((HomeScreenGridItem) -> Unit)? = null | ||||
|  | ||||
|     init { | ||||
|         ViewCompat.setAccessibilityDelegate(this, HomeScreenGridTouchHelper(this)) | ||||
|  | ||||
|         textPaint = TextPaint(Paint.ANTI_ALIAS_FLAG).apply { | ||||
|             color = Color.WHITE | ||||
|             textSize = context.resources.getDimension(R.dimen.smaller_text_size) | ||||
| @@ -706,4 +715,60 @@ class HomeScreenGrid(context: Context, attrs: AttributeSet, defStyle: Int) : Rel | ||||
|  | ||||
|         return null | ||||
|     } | ||||
|  | ||||
|     private inner class HomeScreenGridTouchHelper(host: View) : ExploreByTouchHelper(host) { | ||||
|         override fun getVirtualViewAt(x: Float, y: Float): Int { | ||||
|             val item = isClickingGridItem(x.toInt(), y.toInt()) | ||||
|  | ||||
|             return if (item != null) { | ||||
|                 item.id?.toInt() ?: INVALID_ID | ||||
|             } else { | ||||
|                 INVALID_ID | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         override fun getVisibleVirtualViews(virtualViewIds: MutableList<Int>?) { | ||||
|             val sorted = gridItems.sortedBy { it.top * 100 + it.left } | ||||
|             sorted.forEachIndexed { index, homeScreenGridItem -> | ||||
|                 virtualViewIds?.add(index, homeScreenGridItem.id?.toInt() ?: index) | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         override fun onPopulateNodeForVirtualView(virtualViewId: Int, node: AccessibilityNodeInfoCompat) { | ||||
|             val item = gridItems.firstOrNull { it.id?.toInt() == virtualViewId } ?: throw IllegalArgumentException("Unknown id") | ||||
|  | ||||
|             node.text = item.title | ||||
|  | ||||
|             val viewLocation = IntArray(2) | ||||
|             getLocationOnScreen(viewLocation) | ||||
|  | ||||
|             val viewBounds = getClickableRect(item) | ||||
|             val onScreenBounds = Rect(viewBounds) | ||||
|             onScreenBounds.offset(viewLocation[0], viewLocation[1]) | ||||
|             node.setBoundsInScreen(onScreenBounds) | ||||
|             node.setBoundsInParent(viewBounds) | ||||
|  | ||||
|             node.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK) | ||||
|             node.addAction(AccessibilityNodeInfoCompat.ACTION_LONG_CLICK) | ||||
|             node.setParent(this@HomeScreenGrid) | ||||
|         } | ||||
|  | ||||
|         override fun onPerformActionForVirtualView(virtualViewId: Int, action: Int, arguments: Bundle?): Boolean { | ||||
|             val item = gridItems.firstOrNull { it.id?.toInt() == virtualViewId } ?: throw IllegalArgumentException("Unknown id") | ||||
|             when (action) { | ||||
|                 AccessibilityNodeInfoCompat.ACTION_CLICK -> itemClickListener?.apply { | ||||
|                     invoke(item) | ||||
|                     return true | ||||
|                 } | ||||
|  | ||||
|                 AccessibilityNodeInfoCompat.ACTION_LONG_CLICK -> itemLongClickListener?.apply { | ||||
|                     invoke(item) | ||||
|                     return true | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             return false | ||||
|         } | ||||
|  | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user