Added Accessibility Actions for the context menu actions of each app and entering the preferences activity from home screen

This commit is contained in:
ottoptj 2024-08-30 12:35:16 +03:00
commit a088a1edeb
3 changed files with 148 additions and 109 deletions

View file

@ -16,136 +16,67 @@ import android.widget.EditText
import android.widget.LinearLayout
import android.widget.TextView
import androidx.appcompat.widget.AppCompatButton
import androidx.core.view.ViewCompat
import androidx.lifecycle.lifecycleScope
import eu.ottop.yamlauncher.databinding.ActivityMainBinding
import eu.ottop.yamlauncher.settings.SharedPreferenceManager
import eu.ottop.yamlauncher.utils.Animations
import kotlinx.coroutines.launch
class AppActionMenu {
class AppActionMenu(private val activity: MainActivity, private val binding: ActivityMainBinding, private val launcherApps: LauncherApps, private val searchView: EditText) {
private val animations = Animations(activity)
private val sharedPreferenceManager = SharedPreferenceManager(activity)
fun setActionListeners(
activity: MainActivity,
binding: ActivityMainBinding,
textView: TextView,
editLayout: LinearLayout,
actionMenu: View,
searchView: EditText,
appInfo: ApplicationInfo,
userHandle: UserHandle,
workProfile: Int,
launcherApps: LauncherApps,
appActivity: LauncherActivityInfo?
){
val animations = Animations(activity)
val sharedPreferenceManager = SharedPreferenceManager(activity)
ViewCompat.addAccessibilityAction(textView, "App info") { _, _ ->
appInfo(appActivity, userHandle)
true
}
actionMenu.findViewById<TextView>(R.id.info).setOnClickListener {
// Launch app info in phone settings
if (appActivity != null) {
launcherApps.startAppDetailsActivity(
appActivity.componentName,
userHandle,
null,
null
)
}
appInfo(appActivity, userHandle)
animations.fadeViewOut(actionMenu)
textView.visibility = View.VISIBLE
}
ViewCompat.addAccessibilityAction(textView, "Uninstall app") { _, _ ->
uninstallApp(appInfo, userHandle)
true
}
actionMenu.findViewById<TextView>(R.id.uninstall).setOnClickListener {
val intent = Intent(Intent.ACTION_DELETE)
intent.data = Uri.parse("package:${appInfo.packageName}")
intent.putExtra(Intent.EXTRA_USER, userHandle)
activity.startActivity(intent)
uninstallApp(appInfo, userHandle)
animations.fadeViewOut(actionMenu)
textView.visibility = View.VISIBLE
}
ViewCompat.addAccessibilityAction(textView, "Rename app") { _, _ ->
renameApp(textView, editLayout, actionMenu, appActivity, appInfo, userHandle, workProfile)
true
}
actionMenu.findViewById<TextView>(R.id.rename).setOnClickListener {
textView.visibility = View.INVISIBLE
animations.fadeViewIn(editLayout)
animations.fadeViewOut(actionMenu)
val editText = editLayout.findViewById<EditText>(R.id.appNameEdit)
val resetButton = editLayout.findViewById<AppCompatButton>(R.id.reset)
renameApp(textView, editLayout, actionMenu, appActivity, appInfo, userHandle, workProfile)
}
val app = Triple(appActivity!!, userHandle, workProfile)
searchView.visibility = View.INVISIBLE
editText.requestFocus()
// Open keyboard
val handler = Handler(Looper.getMainLooper())
handler.postDelayed({
val imm =
activity.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT)
}, 100)
binding.root.addOnLayoutChangeListener { _, _, top, _, bottom, _, oldTop, _, oldBottom ->
// If the keyboard is closed, exit editing mode
if (bottom - top > oldBottom - oldTop) {
editLayout.clearFocus()
animations.fadeViewOut(editLayout)
textView.visibility = View.VISIBLE
searchView.visibility = View.VISIBLE
}
}
editText.setOnEditorActionListener { _, actionId, _ ->
// Once the new name is confirmed, close the keyboard, save the new app name and update the apps on screen
if (actionId == EditorInfo.IME_ACTION_DONE) {
val imm =
activity.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(editText.windowToken, 0)
sharedPreferenceManager.setAppName(
appInfo.packageName,
workProfile,
editText.text.toString()
)
activity.lifecycleScope.launch {
activity.applySearch()
}
return@setOnEditorActionListener true
}
false
}
resetButton.setOnClickListener {
// If reset is pressed, close keyboard, remove saved edited name and update the apps on screen
val imm =
activity.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(editLayout.windowToken, 0)
sharedPreferenceManager.resetAppName(
app.first.applicationInfo.packageName,
app.third
)
activity.lifecycleScope.launch {
activity.applySearch()
}
}
ViewCompat.addAccessibilityAction(textView, "Hide app") { _, _ ->
hideApp(editLayout, textView, actionMenu, appInfo, workProfile)
true
}
actionMenu.findViewById<TextView>(R.id.hide).setOnClickListener {
editLayout.visibility = View.GONE
textView.visibility = View.GONE
actionMenu.visibility = View.GONE
activity.lifecycleScope.launch {
sharedPreferenceManager.setAppHidden(appInfo.packageName, workProfile, true)
activity.refreshAppMenu()
}
hideApp(editLayout, textView, actionMenu, appInfo, workProfile)
}
actionMenu.findViewById<TextView>(R.id.close).setOnClickListener {
@ -153,4 +84,107 @@ class AppActionMenu {
textView.visibility = View.VISIBLE
}
}
private fun appInfo(
appActivity: LauncherActivityInfo?,
userHandle: UserHandle
) {
// Launch app info in phone settings
if (appActivity != null) {
launcherApps.startAppDetailsActivity(
appActivity.componentName,
userHandle,
null,
null
)
}
}
private fun uninstallApp(appInfo: ApplicationInfo, userHandle: UserHandle) {
val intent = Intent(Intent.ACTION_DELETE)
intent.data = Uri.parse("package:${appInfo.packageName}")
intent.putExtra(Intent.EXTRA_USER, userHandle)
activity.startActivity(intent)
}
private fun renameApp(textView: TextView, editLayout: LinearLayout, actionMenu: View, appActivity: LauncherActivityInfo?, appInfo: ApplicationInfo, userHandle: UserHandle, workProfile: Int) {
textView.visibility = View.INVISIBLE
animations.fadeViewIn(editLayout)
animations.fadeViewOut(actionMenu)
val editText = editLayout.findViewById<EditText>(R.id.appNameEdit)
val resetButton = editLayout.findViewById<AppCompatButton>(R.id.reset)
val app = Triple(appActivity!!, userHandle, workProfile)
searchView.visibility = View.INVISIBLE
editText.requestFocus()
// Open keyboard
val handler = Handler(Looper.getMainLooper())
handler.postDelayed({
val imm =
activity.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT)
}, 100)
binding.root.addOnLayoutChangeListener { _, _, top, _, bottom, _, oldTop, _, oldBottom ->
// If the keyboard is closed, exit editing mode
if (bottom - top > oldBottom - oldTop) {
editLayout.clearFocus()
animations.fadeViewOut(editLayout)
textView.visibility = View.VISIBLE
searchView.visibility = View.VISIBLE
}
}
editText.setOnEditorActionListener { _, actionId, _ ->
// Once the new name is confirmed, close the keyboard, save the new app name and update the apps on screen
if (actionId == EditorInfo.IME_ACTION_DONE) {
val imm =
activity.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(editText.windowToken, 0)
sharedPreferenceManager.setAppName(
appInfo.packageName,
workProfile,
editText.text.toString()
)
activity.lifecycleScope.launch {
activity.applySearch()
}
return@setOnEditorActionListener true
}
false
}
resetButton.setOnClickListener {
// If reset is pressed, close keyboard, remove saved edited name and update the apps on screen
val imm =
activity.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(editLayout.windowToken, 0)
sharedPreferenceManager.resetAppName(
app.first.applicationInfo.packageName,
app.third
)
activity.lifecycleScope.launch {
activity.applySearch()
}
}
}
private fun hideApp(editLayout: LinearLayout, textView: TextView, actionMenu: View, appInfo: ApplicationInfo, workProfile: Int) {
editLayout.visibility = View.GONE
textView.visibility = View.GONE
actionMenu.visibility = View.GONE
activity.lifecycleScope.launch {
sharedPreferenceManager.setAppHidden(appInfo.packageName, workProfile, true)
activity.refreshAppMenu()
}
}
}

View file

@ -1,7 +1,6 @@
package eu.ottop.yamlauncher
import android.annotation.SuppressLint
import android.content.Context
import android.content.pm.ApplicationInfo
import android.content.pm.LauncherActivityInfo
import android.content.pm.LauncherApps
@ -17,28 +16,30 @@ import android.widget.TextView
import androidx.core.content.res.ResourcesCompat
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.textfield.TextInputEditText
import eu.ottop.yamlauncher.databinding.ActivityMainBinding
import eu.ottop.yamlauncher.settings.SharedPreferenceManager
import eu.ottop.yamlauncher.utils.AppUtils
import eu.ottop.yamlauncher.utils.UIUtils
class AppMenuAdapter(
private val context: Context,
private val activity: MainActivity,
binding: ActivityMainBinding,
private var apps: MutableList<Triple<LauncherActivityInfo, UserHandle, Int>>,
private val itemClickListener: OnItemClickListener,
private val shortcutListener: OnShortcutListener,
private val itemLongClickListener: OnItemLongClickListener,
launcherApps: LauncherApps
private val launcherApps: LauncherApps
) :
RecyclerView.Adapter<AppMenuAdapter.AppViewHolder>() {
// If the menu is opened to select shortcuts, the below variable is set
var shortcutTextView: TextView? = null
private val sharedPreferenceManager = SharedPreferenceManager(context)
private val uiUtils = UIUtils(context)
private val appUtils = AppUtils(context, launcherApps)
private val sharedPreferenceManager = SharedPreferenceManager(activity)
private val uiUtils = UIUtils(activity)
private val appUtils = AppUtils(activity, launcherApps)
private var appActionMenu = AppActionMenu(activity, binding, launcherApps, activity.findViewById(R.id.searchView))
interface OnItemClickListener {
fun onItemClick(appInfo: LauncherActivityInfo, userHandle: UserHandle)
@ -64,7 +65,7 @@ class AppMenuAdapter(
private val listItem: FrameLayout = itemView.findViewById(R.id.listItem)
val textView: TextView = listItem.findViewById(R.id.appName)
val actionMenuLayout: LinearLayout = listItem.findViewById(R.id.actionMenu)
private val editView: LinearLayout = listItem.findViewById(R.id.renameView)
val editView: LinearLayout = listItem.findViewById(R.id.renameView)
val editText: TextInputEditText = editView.findViewById(R.id.appNameEdit)
init {
@ -121,12 +122,12 @@ class AppMenuAdapter(
// Set initial drawables
if (app.third != 0) {
holder.textView.setCompoundDrawablesWithIntrinsicBounds(ResourcesCompat.getDrawable(context.resources, R.drawable.ic_work_app, null),null, ResourcesCompat.getDrawable(context.resources, R.drawable.ic_empty, null),null)
holder.textView.setCompoundDrawablesWithIntrinsicBounds(ResourcesCompat.getDrawable(activity.resources, R.drawable.ic_work_app, null),null, ResourcesCompat.getDrawable(activity.resources, R.drawable.ic_empty, null),null)
holder.textView.compoundDrawables[0].colorFilter =
BlendModeColorFilter(sharedPreferenceManager.getTextColor(), BlendMode.SRC_ATOP)
}
else {
holder.textView.setCompoundDrawablesWithIntrinsicBounds(ResourcesCompat.getDrawable(context.resources, R.drawable.ic_empty, null),null,ResourcesCompat.getDrawable(context.resources, R.drawable.ic_empty, null),null)
holder.textView.setCompoundDrawablesWithIntrinsicBounds(ResourcesCompat.getDrawable(activity.resources, R.drawable.ic_empty, null),null,ResourcesCompat.getDrawable(activity.resources, R.drawable.ic_empty, null),null)
}
uiUtils.setAppAlignment(holder.textView, holder.editText)
@ -142,7 +143,7 @@ class AppMenuAdapter(
holder.textView.setTextColor(sharedPreferenceManager.getTextColor())
// Set app name on the menu. If the app has been uninstalled, replace it with "Removing" until the app menu updates.
val appLabel: CharSequence = appInfo?.let { context.packageManager.getApplicationLabel(it) } ?: "Removing..."
val appLabel: CharSequence = appInfo?.let { activity.packageManager.getApplicationLabel(it) } ?: "Removing..."
if (appInfo != null) {
holder.textView.text = sharedPreferenceManager.getAppName(
@ -165,6 +166,21 @@ class AppMenuAdapter(
else {holder.textView.text = appLabel}
holder.textView.visibility = View.VISIBLE
if (appInfo != null) {
val appActivity = launcherApps.getActivityList(appInfo.packageName, app.second).firstOrNull()
appActionMenu.setActionListeners(
holder.textView,
holder.editView,
holder.actionMenuLayout,
appInfo,
app.second,
app.third,
appActivity
)
}
}
override fun getItemCount(): Int {

View file

@ -28,6 +28,7 @@ import androidx.activity.OnBackPressedCallback
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.res.ResourcesCompat
import androidx.core.view.ViewCompat
import androidx.core.view.marginLeft
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
@ -64,7 +65,6 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
private lateinit var uiUtils: UIUtils
private lateinit var gestureUtils: GestureUtils
private var appActionMenu = AppActionMenu()
private val appMenuLinearLayoutManager = AppMenuLinearLayoutManager(this@MainActivity)
private val appMenuEdgeFactory = AppMenuEdgeFactory(this@MainActivity)
@ -317,6 +317,11 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
true
}
ViewCompat.addAccessibilityAction(binding.homeView, "Preferences") { _, _ ->
startActivity(Intent(this@MainActivity, SettingsActivity::class.java))
true
}
// Return to home on back
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
@ -526,7 +531,7 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
}
private suspend fun setupRecyclerView(newApps: MutableList<Triple<LauncherActivityInfo, UserHandle, Int>>) {
adapter = AppMenuAdapter(this@MainActivity, newApps, this@MainActivity, this@MainActivity, this@MainActivity, launcherApps)
adapter = AppMenuAdapter(this@MainActivity, binding, newApps, this@MainActivity, this@MainActivity, this@MainActivity, launcherApps)
appMenuLinearLayoutManager.stackFromEnd = true
recyclerView = findViewById(R.id.recyclerView)
withContext(Dispatchers.Main) {
@ -696,22 +701,6 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
) {
textView.visibility = View.INVISIBLE
animations.fadeViewIn(actionMenuLayout)
val appActivity =
launcherApps.getActivityList(appInfo.applicationInfo.packageName, userHandle)
.firstOrNull()
appActionMenu.setActionListeners(
this@MainActivity,
binding,
textView,
editView,
actionMenuLayout,
searchView,
appInfo.applicationInfo,
userHandle,
userProfile,
launcherApps,
appActivity
)
}
open inner class GestureListener : GestureDetector.SimpleOnGestureListener() {