diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml index b268ef3..81acdf9 100644 --- a/.idea/deploymentTargetSelector.xml +++ b/.idea/deploymentTargetSelector.xml @@ -4,6 +4,14 @@ diff --git a/app/src/main/java/de/jrpie/android/launcher/Functions.kt b/app/src/main/java/de/jrpie/android/launcher/Functions.kt index 648894d..aa5193a 100644 --- a/app/src/main/java/de/jrpie/android/launcher/Functions.kt +++ b/app/src/main/java/de/jrpie/android/launcher/Functions.kt @@ -1,12 +1,15 @@ package de.jrpie.android.launcher import android.app.Activity +import android.app.ActivityOptions import android.app.AlertDialog import android.app.Service import android.app.role.RoleManager import android.content.Context import android.content.Intent import android.content.SharedPreferences +import android.content.pm.ActivityInfo +import android.content.pm.LauncherActivityInfo import android.content.pm.LauncherApps import android.content.pm.PackageManager import android.graphics.BlendMode @@ -15,12 +18,14 @@ import android.graphics.ColorMatrix import android.graphics.ColorMatrixColorFilter import android.graphics.PorterDuff import android.graphics.PorterDuffColorFilter +import android.graphics.Rect import android.graphics.drawable.Drawable import android.media.AudioManager import android.net.Uri import android.os.Build import android.os.Bundle import android.os.SystemClock +import android.os.UserHandle import android.os.UserManager import android.provider.Settings import android.util.DisplayMetrics @@ -39,10 +44,12 @@ import android.widget.Toast import de.jrpie.android.launcher.list.ListActivity import de.jrpie.android.launcher.list.apps.AppInfo import de.jrpie.android.launcher.list.apps.AppsRecyclerAdapter +import de.jrpie.android.launcher.list.intendedChoosePause import de.jrpie.android.launcher.list.other.LauncherAction import de.jrpie.android.launcher.settings.SettingsActivity import de.jrpie.android.launcher.settings.intendedSettingsPause import de.jrpie.android.launcher.tutorial.TutorialActivity +import kotlin.contracts.contract /* Preference Key Constants */ @@ -220,17 +227,37 @@ fun audioVolumeDown(activity: Activity) { /* --- */ -fun launchApp(packageName: String, user: Int?, context: Context) { +fun getUserFromId(user: Int?, context: Context): UserHandle? { + val userManager = context.getSystemService(Service.USER_SERVICE) as UserManager + return userManager.userProfiles.firstOrNull { it.hashCode() == user } +} +fun getLauncherActivityInfo(packageName: String, user: Int?, context: Context): LauncherActivityInfo? { + val launcherApps = context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps + return getUserFromId(user,context)?.let { + userHandle -> launcherApps.getActivityList(packageName, userHandle).firstOrNull() + } +} +fun uninstallApp(packageName: String, user: Int?, activity: Activity) { + Log.i("Launcher", "uninstalling $packageName ($user)") + val intent = Intent(Intent.ACTION_UNINSTALL_PACKAGE) + intent.data = Uri.parse("package:$packageName") + getUserFromId(user, activity)?.let { + user -> intent.putExtra(Intent.EXTRA_USER, user) + } + + intent.putExtra(Intent.EXTRA_RETURN_RESULT, true) + activity.startActivityForResult(intent, + REQUEST_UNINSTALL + ) +} + +fun launchApp(packageName: String, user: Int?, context: Context, rect: Rect? = null) { Log.i("Launcher", "Starting: " + packageName + " (user " +user.toString()+ ")") if (user != null) { val launcherApps = context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps - val userManager = context.getSystemService(Service.USER_SERVICE) as UserManager - userManager.userProfiles.firstOrNull { it.hashCode() == user }?.let { - userHandle -> launcherApps.getActivityList(packageName, userHandle).firstOrNull()?.let { - app -> launcherApps.startMainActivity(app.componentName, userHandle, null, null) - return - - } + getLauncherActivityInfo(packageName,user,context)?.let { + app -> launcherApps.startMainActivity(app.componentName, app.user, rect, null) + return } } @@ -251,6 +278,7 @@ fun launchApp(packageName: String, user: Int?, context: Context) { ) { _, _ -> openAppSettings( packageName, + user, context ) } @@ -322,10 +350,11 @@ fun resetToDarkTheme(activity: Activity) { } -fun openAppSettings(pkg: String, context: Context) { - val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) - intent.data = Uri.parse("package:$pkg") - context.startActivity(intent) +fun openAppSettings(packageName: String, user: Int?, context: Context, sourceBounds: Rect? = null, opts: Bundle? = null) { + val launcherApps = context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps + getLauncherActivityInfo(packageName, user, context)?.let { + app -> launcherApps.startAppDetailsActivity(app.componentName, app.user, sourceBounds, opts) + } } fun openSettings(activity: Activity) { @@ -346,8 +375,7 @@ fun openAppsList(activity: Activity){ fun getAppIcon(context: Context, packageName: String, user: Int?): Drawable { if (user != null) { val launcherApps = context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps - val userManager = context.getSystemService(Service.USER_SERVICE) as UserManager - userManager.userProfiles.firstOrNull { it.hashCode() == user }?.let { + getUserFromId(user,context)?.let { userHandle -> launcherApps.getActivityList(packageName, userHandle).firstOrNull()?.let { app -> return app.getBadgedIcon(0) } diff --git a/app/src/main/java/de/jrpie/android/launcher/list/apps/AppsRecyclerAdapter.kt b/app/src/main/java/de/jrpie/android/launcher/list/apps/AppsRecyclerAdapter.kt index 490d264..042c71c 100644 --- a/app/src/main/java/de/jrpie/android/launcher/list/apps/AppsRecyclerAdapter.kt +++ b/app/src/main/java/de/jrpie/android/launcher/list/apps/AppsRecyclerAdapter.kt @@ -3,6 +3,7 @@ package de.jrpie.android.launcher.list.apps import android.app.Activity import android.content.Context import android.content.Intent +import android.graphics.Rect import android.net.Uri import android.os.AsyncTask import android.view.LayoutInflater @@ -27,6 +28,7 @@ import de.jrpie.android.launcher.list.intendedChoosePause import de.jrpie.android.launcher.loadApps import de.jrpie.android.launcher.openAppSettings import de.jrpie.android.launcher.transformGrayscale +import de.jrpie.android.launcher.uninstallApp import java.util.* /** @@ -58,8 +60,9 @@ class AppsRecyclerAdapter(val activity: Activity, val appUser = appsListDisplayed[pos].user when (intention){ ListActivity.ListActivityIntention.VIEW -> { - launchApp(appPackageName, appUser, activity) - + val rect = Rect() + img.getGlobalVisibleRect(rect) + launchApp(appPackageName, appUser, activity, rect) } ListActivity.ListActivityIntention.PICK -> { val returnIntent = Intent() @@ -78,6 +81,7 @@ class AppsRecyclerAdapter(val activity: Activity, override fun onBindViewHolder(viewHolder: ViewHolder, i: Int) { val appLabel = appsListDisplayed[i].label.toString() val appPackageName = appsListDisplayed[i].packageName.toString() + val appUser = appsListDisplayed[i].user val appIcon = appsListDisplayed[i].icon val isSystemApp = appsListDisplayed[i].isSystemApp @@ -95,10 +99,10 @@ class AppsRecyclerAdapter(val activity: Activity, else { viewHolder.menuDots.visibility = View.VISIBLE - viewHolder.menuDots.setOnClickListener{ showOptionsPopup(viewHolder, appPackageName) } - viewHolder.menuDots.setOnLongClickListener{ showOptionsPopup(viewHolder, appPackageName) } - viewHolder.textView.setOnLongClickListener{ showOptionsPopup(viewHolder, appPackageName) } - viewHolder.img.setOnLongClickListener{ showOptionsPopup(viewHolder, appPackageName) } + viewHolder.menuDots.setOnClickListener{ showOptionsPopup(viewHolder, appPackageName, appUser) } + viewHolder.menuDots.setOnLongClickListener{ showOptionsPopup(viewHolder, appPackageName, appUser) } + viewHolder.textView.setOnLongClickListener{ showOptionsPopup(viewHolder, appPackageName, appUser) } + viewHolder.img.setOnLongClickListener{ showOptionsPopup(viewHolder, appPackageName, appUser) } // ensure onClicks are actually caught viewHolder.textView.setOnClickListener{ viewHolder.onClick(viewHolder.textView) } @@ -106,9 +110,8 @@ class AppsRecyclerAdapter(val activity: Activity, } } - // TODO fixme: handle work profile apps @Suppress("SameReturnValue") - private fun showOptionsPopup(viewHolder: ViewHolder, appPackageName: String): Boolean { + private fun showOptionsPopup(viewHolder: ViewHolder, appPackageName: String, user: Int?): Boolean { //create the popup menu val popup = PopupMenu(activity, viewHolder.menuDots) @@ -116,23 +119,14 @@ class AppsRecyclerAdapter(val activity: Activity, popup.setOnMenuItemClickListener { when (it.itemId) { - R.id.app_menu_delete -> { // delete + R.id.app_menu_delete -> { intendedChoosePause = true - val intent = Intent(Intent.ACTION_UNINSTALL_PACKAGE) - intent.data = Uri.parse("package:$appPackageName") - intent.putExtra(Intent.EXTRA_RETURN_RESULT, true) - activity.startActivityForResult(intent, - REQUEST_UNINSTALL - ) - + uninstallApp(appPackageName, user, activity) true } - R.id.app_menu_info -> { // open app settings + R.id.app_menu_info -> { intendedChoosePause = true - openAppSettings( - appPackageName, - activity - ) + openAppSettings(appPackageName, user, activity) true } else -> false diff --git a/app/src/main/java/de/jrpie/android/launcher/settings/actions/SettingsFragmentActions.kt b/app/src/main/java/de/jrpie/android/launcher/settings/actions/SettingsFragmentActions.kt index 62b4758..5bfe246 100644 --- a/app/src/main/java/de/jrpie/android/launcher/settings/actions/SettingsFragmentActions.kt +++ b/app/src/main/java/de/jrpie/android/launcher/settings/actions/SettingsFragmentActions.kt @@ -2,7 +2,6 @@ package de.jrpie.android.launcher.settings.actions import android.content.ActivityNotFoundException import android.content.Intent -import android.content.SharedPreferences import android.content.SharedPreferences.OnSharedPreferenceChangeListener import android.net.Uri import android.os.Bundle @@ -11,10 +10,14 @@ import android.view.View import android.view.ViewGroup import android.widget.Toast import androidx.fragment.app.Fragment -import de.jrpie.android.launcher.* +import de.jrpie.android.launcher.R +import de.jrpie.android.launcher.UIObject import de.jrpie.android.launcher.databinding.SettingsActionsBinding +import de.jrpie.android.launcher.getPreferences import de.jrpie.android.launcher.list.ListActivity +import de.jrpie.android.launcher.setButtonColor import de.jrpie.android.launcher.settings.intendedSettingsPause +import de.jrpie.android.launcher.vibrantColor /** @@ -25,7 +28,8 @@ import de.jrpie.android.launcher.settings.intendedSettingsPause * It also allows the user to view all apps ([ListActivity]) or install new ones. */ -class SettingsFragmentActions : Fragment(), UIObject { +class +SettingsFragmentActions : Fragment(), UIObject { private var binding: SettingsActionsBinding? = null diff --git a/app/src/main/java/de/jrpie/android/launcher/settings/meta/SettingsFragmentMeta.kt b/app/src/main/java/de/jrpie/android/launcher/settings/meta/SettingsFragmentMeta.kt index 463b7f3..90a04c9 100644 --- a/app/src/main/java/de/jrpie/android/launcher/settings/meta/SettingsFragmentMeta.kt +++ b/app/src/main/java/de/jrpie/android/launcher/settings/meta/SettingsFragmentMeta.kt @@ -50,7 +50,7 @@ class SettingsFragmentMeta : Fragment(), UIObject { private fun rateIntentForUrl(url: String): Intent { val intent = Intent( Intent.ACTION_VIEW, - Uri.parse(String.format("%s?id=%s", url, this.context!!.packageName)) + Uri.parse(String.format("%s?id=%s", url, this.requireContext().packageName)) ) var flags = Intent.FLAG_ACTIVITY_NO_HISTORY or Intent.FLAG_ACTIVITY_MULTIPLE_TASK flags = flags or Intent.FLAG_ACTIVITY_NEW_DOCUMENT @@ -59,7 +59,6 @@ class SettingsFragmentMeta : Fragment(), UIObject { } override fun applyTheme() { - setButtonColor(binding.settingsMetaButtonSelectLauncher, vibrantColor) setButtonColor(binding.settingsMetaButtonViewTutorial, vibrantColor) setButtonColor(binding.settingsMetaButtonResetSettings, vibrantColor) setButtonColor(binding.settingsMetaButtonReportBug, vibrantColor) @@ -70,12 +69,6 @@ class SettingsFragmentMeta : Fragment(), UIObject { override fun setOnClicks() { - binding.settingsMetaButtonSelectLauncher.setOnClickListener { - intendedSettingsPause = true - val callHomeSettingIntent = Intent(Settings.ACTION_HOME_SETTINGS) - startActivity(callHomeSettingIntent) - } - binding.settingsMetaButtonViewTutorial.setOnClickListener { intendedSettingsPause = true startActivity(Intent(this.context, TutorialActivity::class.java)) @@ -102,7 +95,7 @@ class SettingsFragmentMeta : Fragment(), UIObject { intendedSettingsPause = true openNewTabWindow( getString(R.string.settings_meta_report_bug_link), - context!! + requireContext() ) } @@ -113,7 +106,7 @@ class SettingsFragmentMeta : Fragment(), UIObject { intendedSettingsPause = true openNewTabWindow( getString(R.string.settings_meta_contact_url), - context!! + requireContext() ) } @@ -122,7 +115,7 @@ class SettingsFragmentMeta : Fragment(), UIObject { intendedSettingsPause = true openNewTabWindow( getString(R.string.settings_meta_fork_contact_url), - context!! + requireContext() ) } @@ -131,7 +124,7 @@ class SettingsFragmentMeta : Fragment(), UIObject { intendedSettingsPause = true openNewTabWindow( getString(R.string.settings_meta_privacy_url), - context!! + requireContext() ) } diff --git a/app/src/main/res/layout/settings_meta.xml b/app/src/main/res/layout/settings_meta.xml index 8cb9802..af9633a 100644 --- a/app/src/main/res/layout/settings_meta.xml +++ b/app/src/main/res/layout/settings_meta.xml @@ -13,13 +13,6 @@ android:paddingRight="32sp" tools:context=".settings.meta.SettingsFragmentMeta"> -