From ebc2e5ca2ab58058ea262ebdb3ec5695019de896 Mon Sep 17 00:00:00 2001 From: Josia Pietsch Date: Tue, 30 Jul 2024 20:07:29 +0200 Subject: [PATCH 001/374] version j-0.0.5 --- .idea/migrations.xml | 10 ++++++++++ app/build.gradle | 16 ++++++++-------- .../launcher/SettingsFragmentLauncher.kt | 10 ++++++---- app/src/main/res/values-de/strings.xml | 2 +- app/src/main/res/values/strings.xml | 4 ++-- 5 files changed, 27 insertions(+), 15 deletions(-) create mode 100644 .idea/migrations.xml diff --git a/.idea/migrations.xml b/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 5f7bdc6..6e41727 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,8 +10,8 @@ android { applicationId "de.jrpie.android.launcher" minSdkVersion 21 targetSdkVersion 35 - versionCode 16 - versionName "j-0.0.4" + versionCode 17 + versionName "j-0.0.5" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } @@ -32,14 +32,14 @@ android { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation 'androidx.appcompat:appcompat:1.1.0' - implementation 'androidx.core:core-ktx:1.2.0' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.appcompat:appcompat:1.7.0' + implementation 'androidx.core:core-ktx:1.13.1' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.legacy:legacy-support-v4:1.0.0' testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test.ext:junit:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' - implementation 'com.google.android.material:material:1.1.0' + androidTestImplementation 'androidx.test.ext:junit:1.2.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1' + implementation 'com.google.android.material:material:1.12.0' implementation 'androidx.gridlayout:gridlayout:1.0.0' implementation 'androidx.palette:palette-ktx:1.0.0' } diff --git a/app/src/main/java/de/jrpie/android/launcher/settings/launcher/SettingsFragmentLauncher.kt b/app/src/main/java/de/jrpie/android/launcher/settings/launcher/SettingsFragmentLauncher.kt index eb54d68..85fe6fd 100644 --- a/app/src/main/java/de/jrpie/android/launcher/settings/launcher/SettingsFragmentLauncher.kt +++ b/app/src/main/java/de/jrpie/android/launcher/settings/launcher/SettingsFragmentLauncher.kt @@ -101,12 +101,14 @@ class SettingsFragmentLauncher : Fragment(), UIObject { bindSwitchToPref(settings_launcher_switch_auto_launch, PREF_SEARCH_AUTO_LAUNCH, false) {} bindSwitchToPref(settings_launcher_switch_auto_keyboard, PREF_SEARCH_AUTO_KEYBOARD, true) {} bindSwitchToPref(settings_launcher_switch_enable_double, PREF_DOUBLE_ACTIONS_ENABLED, false) { - intendedSettingsPause = true - activity?.recreate() + //intendedSettingsPause = true + // TODO fixme: This causes the app to crash on some devices. + //activity?.recreate() } bindSwitchToPref(settings_launcher_switch_enable_edge, PREF_EDGE_ACTIONS_ENABLED, false) { - intendedSettingsPause = true - activity?.recreate() + //intendedSettingsPause = true + // TODO fixme + //activity?.recreate() } settings_seekbar_sensitivity.setOnSeekBarChangeListener( diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 8518b84..6524a4a 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -158,7 +158,7 @@ Du kannst deine Einstellungen auch später noch ändern. Los gehts! - Du bist bereit loszulegen!\n\nIch hoffe diese App ist sehr wertvoll für dich!\n\n- Finn (der Entwickler) + Du bist bereit loszulegen!\n\nIch hoffe diese App ist nützlich für dich!\n\n- Finn (der Entwickler)\n\tund Josia (der einige Änderungen vorgenommen hat und den Fork μLauncher entwickelt. Starten Einstellungen diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e81ae78..a21a62c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -4,7 +4,7 @@ - General - --> - Launcher + μLauncher V3RYR4ND0MK3YCR4P org.lineageos.etar + ws.xsoh.etar com.google.android.calendar com.samsung.android.calendar From 7a60611ec5b26adbcc67a20d27b96ae08de3647c Mon Sep 17 00:00:00 2001 From: Josia Pietsch Date: Fri, 2 Aug 2024 22:28:37 +0200 Subject: [PATCH 007/374] feature: use RoleManager to set as default home --- .../de/jrpie/android/launcher/Functions.kt | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) 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 c40ab9b..a9d7f6c 100644 --- a/app/src/main/java/de/jrpie/android/launcher/Functions.kt +++ b/app/src/main/java/de/jrpie/android/launcher/Functions.kt @@ -2,23 +2,26 @@ package de.jrpie.android.launcher import android.app.Activity import android.app.AlertDialog -import android.content.ComponentName +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.LauncherApps import android.content.pm.PackageManager -import android.content.pm.ResolveInfo import android.graphics.BlendMode import android.graphics.BlendModeColorFilter import android.graphics.ColorMatrix import android.graphics.ColorMatrixColorFilter import android.graphics.PorterDuff import android.graphics.PorterDuffColorFilter +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.UserManager import android.provider.Settings import android.util.DisplayMetrics import android.util.Log @@ -78,6 +81,8 @@ var vibrantColor = 0 const val REQUEST_CHOOSE_APP = 1 const val REQUEST_UNINSTALL = 2 +const val REQUEST_SET_DEFAULT_HOME = 42 + /* Animate */ // Taken from https://stackoverflow.com/questions/47293269 @@ -105,6 +110,17 @@ fun getPreferences(context: Context): SharedPreferences{ } fun setDefaultHomeScreen(context: Context, checkDefault: Boolean = false) { + + if (checkDefault + && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q + && context is Activity) { + val roleManager = context.getSystemService(RoleManager::class.java) + if(!roleManager.isRoleHeld(RoleManager.ROLE_HOME)) { + context.startActivityForResult(roleManager.createRequestRoleIntent(RoleManager.ROLE_HOME), REQUEST_SET_DEFAULT_HOME) + } + return + } + if(checkDefault) { val testIntent = Intent(Intent.ACTION_MAIN) testIntent.addCategory(Intent.CATEGORY_HOME) From 500062b29baedceb8064d3b36f77e2cfb39b5da7 Mon Sep 17 00:00:00 2001 From: Josia Pietsch Date: Fri, 2 Aug 2024 22:32:35 +0200 Subject: [PATCH 008/374] feature: work profile --- README.md | 1 + app/src/main/AndroidManifest.xml | 1 + .../de/jrpie/android/launcher/Functions.kt | 83 +++++++++++++++---- .../java/de/jrpie/android/launcher/Gesture.kt | 18 +++- .../de/jrpie/android/launcher/HomeActivity.kt | 2 +- .../android/launcher/list/apps/AppInfo.kt | 1 + .../launcher/list/apps/AppsRecyclerAdapter.kt | 12 ++- .../list/other/OtherRecyclerAdapter.kt | 6 +- .../SettingsFragmentActionsRecycler.kt | 5 +- 9 files changed, 100 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 2e25e3e..51ae856 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ This is a fork of [finnmglas's app Launcher][original-repo]. ## Notable changes: * Edge gestures: There is a setting to allow distinguishing swiping at the edges of the screen from swiping in the center. +* Compatible with [work profile](https://www.android.com/enterprise/work-profile/), so apps like [Shelter](https://gitea.angry.im/PeterCxy/Shelter) can be used. ### Visual * This app uses the system wallpaper instead of a custom solution. diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ec99e9b..5df0438 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -6,6 +6,7 @@ + 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 a9d7f6c..dd70db0 100644 --- a/app/src/main/java/de/jrpie/android/launcher/Functions.kt +++ b/app/src/main/java/de/jrpie/android/launcher/Functions.kt @@ -67,6 +67,8 @@ const val PREF_STARTED_TIME = "firstStartup" const val PREF_VERSION = "version" +const val INVALID_USER = -1 + /* Objects used by multiple activities */ val appsList: MutableList = ArrayList() @@ -153,14 +155,15 @@ private fun getIntent(packageName: String, context: Context): Intent? { } fun launch( - data: String, activity: Activity, + data: String, user: Int?, + activity: Activity, animationIn: Int = android.R.anim.fade_in, animationOut: Int = android.R.anim.fade_out ) { if (LauncherAction.isOtherAction(data)) { // [type]:[info] LauncherAction.byId(data)?.let {it.launch(activity) } } - else launchApp(data, activity) // app + else launchApp(data, user, activity) // app activity.overridePendingTransition(animationIn, animationOut) } @@ -217,7 +220,20 @@ fun audioVolumeDown(activity: Activity) { /* --- */ -fun launchApp(packageName: String, context: Context) { +fun launchApp(packageName: String, user: Int?, context: Context) { + 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 + + } + } + } + val intent = getIntent(packageName, context) if (intent != null) { @@ -327,25 +343,57 @@ fun openAppsList(activity: Activity){ activity.startActivity(intent) } +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 { + userHandle -> launcherApps.getActivityList(packageName, userHandle).firstOrNull()?.let { + app -> return app.getBadgedIcon(0) + } + } + } + return context.packageManager.getApplicationIcon(packageName) +} + /** * [loadApps] is used to speed up the [AppsRecyclerAdapter] loading time, * as it caches all the apps and allows for fast access to the data. */ -fun loadApps(packageManager: PackageManager) { +fun loadApps(packageManager: PackageManager, context: Context) { val loadList = mutableListOf() - val i = Intent(Intent.ACTION_MAIN, null) - i.addCategory(Intent.CATEGORY_LAUNCHER) - val allApps = packageManager.queryIntentActivities(i, 0) - for (ri in allApps) { - val app = AppInfo() - app.label = ri.loadLabel(packageManager) - app.packageName = ri.activityInfo.packageName - app.icon = ri.activityInfo.loadIcon(packageManager) - loadList.add(app) - } - loadList.sortBy { it.label.toString() } + val launcherApps = context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps + val userManager = context.getSystemService(Service.USER_SERVICE) as UserManager + // TODO: shortcuts - launcherApps.getShortcuts() + val users = userManager.userProfiles + for(user in users) { + for (activityInfo in launcherApps.getActivityList(null,user)) { + val app = AppInfo() + app.label = activityInfo.label + app.packageName = activityInfo.applicationInfo.packageName + app.icon = activityInfo.getBadgedIcon(0) + app.user = user.hashCode() + loadList.add(app) + } + } + + + // fallback option + if(loadList.isEmpty()){ + Log.i("Launcher", "using fallback option to load packages") + val i = Intent(Intent.ACTION_MAIN, null) + i.addCategory(Intent.CATEGORY_LAUNCHER) + val allApps = packageManager.queryIntentActivities(i, 0) + for (ri in allApps) { + val app = AppInfo() + app.label = ri.loadLabel(packageManager) + app.packageName = ri.activityInfo.packageName + app.icon = ri.activityInfo.loadIcon(packageManager) + loadList.add(app) + } + } appsList.clear() appsList.addAll(loadList) } @@ -404,9 +452,12 @@ fun setWindowFlags(window: Window) { // Used in Tutorial and Settings `ActivityOnResult` fun saveListActivityChoice(context: Context, data: Intent?) { val value = data?.getStringExtra("value") + var user = data?.getIntExtra("user", INVALID_USER) + user = user?.let{ if(it == INVALID_USER) null else it } + val forGesture = data?.getStringExtra("forGesture") ?: return - Gesture.byId(forGesture)?.setApp(context, value.toString()) + Gesture.byId(forGesture)?.setApp(context, value.toString(), user) loadSettings(context) } diff --git a/app/src/main/java/de/jrpie/android/launcher/Gesture.kt b/app/src/main/java/de/jrpie/android/launcher/Gesture.kt index 8d70340..fc48d1d 100644 --- a/app/src/main/java/de/jrpie/android/launcher/Gesture.kt +++ b/app/src/main/java/de/jrpie/android/launcher/Gesture.kt @@ -41,8 +41,12 @@ enum class Gesture (val id: String, private val labelResource: Int, TOP, BOTTOM, LEFT, RIGHT } - fun getApp(context: Context): String { - return getPreferences(context).getString(this.id, "")!! + fun getApp(context: Context): Pair { + val preferences = getPreferences(context) + var packageName = preferences.getString(this.id, "")!! + var u: Int? = preferences.getInt(this.id + "_user", INVALID_USER) + u = if(u == INVALID_USER) null else u + return Pair(packageName,u) } fun removeApp(context: Context) { @@ -51,10 +55,15 @@ enum class Gesture (val id: String, private val labelResource: Int, .apply() } - fun setApp(context: Context, app: String) { + fun setApp(context: Context, app: String, user: Int?) { getPreferences(context).edit() .putString(this.id, app) .apply() + + val u = user?: INVALID_USER + getPreferences(context).edit() + .putInt(this.id + "_user", u) + .apply() } fun getLabel(context: Context): String { @@ -132,7 +141,8 @@ enum class Gesture (val id: String, private val labelResource: Int, } operator fun invoke(activity: Activity) { - launch(this.getApp(activity), activity, this.animationIn, this.animationOut) + val app = this.getApp(activity) + launch(app.first, app.second, activity, this.animationIn, this.animationOut) } companion object { diff --git a/app/src/main/java/de/jrpie/android/launcher/HomeActivity.kt b/app/src/main/java/de/jrpie/android/launcher/HomeActivity.kt index 10529ed..fd20091 100644 --- a/app/src/main/java/de/jrpie/android/launcher/HomeActivity.kt +++ b/app/src/main/java/de/jrpie/android/launcher/HomeActivity.kt @@ -87,7 +87,7 @@ class HomeActivity: UIObject, AppCompatActivity(), } // Preload apps to speed up the Apps Recycler - AsyncTask.execute { loadApps(packageManager) } + AsyncTask.execute { loadApps(packageManager, applicationContext) } // Initialise layout binding = HomeBinding.inflate(layoutInflater) diff --git a/app/src/main/java/de/jrpie/android/launcher/list/apps/AppInfo.kt b/app/src/main/java/de/jrpie/android/launcher/list/apps/AppInfo.kt index 0c99757..f19fd0e 100644 --- a/app/src/main/java/de/jrpie/android/launcher/list/apps/AppInfo.kt +++ b/app/src/main/java/de/jrpie/android/launcher/list/apps/AppInfo.kt @@ -8,6 +8,7 @@ import android.graphics.drawable.Drawable * Represents an app installed on the users device. */ class AppInfo { + var user: Int? = null var label: CharSequence? = null var packageName: CharSequence? = null var icon: Drawable? = null 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 a0c76da..d0d70b5 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 @@ -21,6 +21,7 @@ import de.jrpie.android.launcher.appsList import de.jrpie.android.launcher.getPreferences import de.jrpie.android.launcher.getSavedTheme import de.jrpie.android.launcher.launch +import de.jrpie.android.launcher.launchApp import de.jrpie.android.launcher.list.ListActivity import de.jrpie.android.launcher.list.intendedChoosePause import de.jrpie.android.launcher.loadApps @@ -54,9 +55,10 @@ class AppsRecyclerAdapter(val activity: Activity, val pos = adapterPosition val context: Context = v.context val appPackageName = appsListDisplayed[pos].packageName.toString() - + val appUser = appsListDisplayed[pos].user when (intention){ ListActivity.ListActivityIntention.VIEW -> { + launchApp(appPackageName, appUser, activity) val launchIntent: Intent = context.packageManager .getLaunchIntentForPackage(appPackageName)!! context.startActivity(launchIntent) @@ -64,6 +66,7 @@ class AppsRecyclerAdapter(val activity: Activity, ListActivity.ListActivityIntention.PICK -> { val returnIntent = Intent() returnIntent.putExtra("value", appPackageName) + appUser?.let{ returnIntent.putExtra("user", it) } returnIntent.putExtra("forGesture", forGesture) activity.setResult(REQUEST_CHOOSE_APP, returnIntent) activity.finish() @@ -152,9 +155,9 @@ class AppsRecyclerAdapter(val activity: Activity, init { // Load the apps if (appsList.size == 0) - loadApps(activity.packageManager) + loadApps(activity.packageManager, activity) else { - AsyncTask.execute { loadApps(activity.packageManager) } + AsyncTask.execute { loadApps(activity.packageManager, activity) } notifyDataSetChanged() } @@ -193,7 +196,8 @@ class AppsRecyclerAdapter(val activity: Activity, // modifiable at some later point. if (appsListDisplayed.size == 1 && intention == ListActivity.ListActivityIntention.VIEW && getPreferences(activity).getBoolean(PREF_SEARCH_AUTO_LAUNCH, false)) { - launch(appsListDisplayed[0].packageName.toString(), activity) + val info = appsListDisplayed[0] + launch(info.packageName.toString(), info.user, activity) val inputMethodManager = activity.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager inputMethodManager.hideSoftInputFromWindow(View(activity).windowToken, 0) diff --git a/app/src/main/java/de/jrpie/android/launcher/list/other/OtherRecyclerAdapter.kt b/app/src/main/java/de/jrpie/android/launcher/list/other/OtherRecyclerAdapter.kt index 1e04a0d..0b54fa6 100644 --- a/app/src/main/java/de/jrpie/android/launcher/list/other/OtherRecyclerAdapter.kt +++ b/app/src/main/java/de/jrpie/android/launcher/list/other/OtherRecyclerAdapter.kt @@ -8,6 +8,7 @@ import android.view.ViewGroup import android.widget.ImageView import android.widget.TextView import androidx.recyclerview.widget.RecyclerView +import de.jrpie.android.launcher.INVALID_USER import de.jrpie.android.launcher.R import de.jrpie.android.launcher.REQUEST_CHOOSE_APP import de.jrpie.android.launcher.list.forGesture @@ -56,10 +57,11 @@ class OtherRecyclerAdapter(val activity: Activity): return ViewHolder(view) } - private fun returnChoiceIntent(forApp: String, value: String) { + private fun returnChoiceIntent(forGesture: String, value: String) { val returnIntent = Intent() returnIntent.putExtra("value", value) - returnIntent.putExtra("forGesture", forApp) + returnIntent.putExtra("forGesture", forGesture) + returnIntent.putExtra("user", INVALID_USER) activity.setResult(REQUEST_CHOOSE_APP, returnIntent) activity.finish() } diff --git a/app/src/main/java/de/jrpie/android/launcher/settings/actions/SettingsFragmentActionsRecycler.kt b/app/src/main/java/de/jrpie/android/launcher/settings/actions/SettingsFragmentActionsRecycler.kt index 0685a87..3e609c4 100644 --- a/app/src/main/java/de/jrpie/android/launcher/settings/actions/SettingsFragmentActionsRecycler.kt +++ b/app/src/main/java/de/jrpie/android/launcher/settings/actions/SettingsFragmentActionsRecycler.kt @@ -80,7 +80,8 @@ class ActionsRecyclerAdapter(val activity: Activity): viewHolder.img ) fun updateViewHolder() { - val content = gesture.getApp(activity) + val app = gesture.getApp(activity) + val content = app.first if (content == ""){ viewHolder.img.visibility = View.INVISIBLE viewHolder.removeAction.visibility = View.GONE @@ -93,7 +94,7 @@ class ActionsRecyclerAdapter(val activity: Activity): } else { // Set image icon (by packageName) try { - viewHolder.img.setImageDrawable(activity.packageManager.getApplicationIcon(content)) + viewHolder.img.setImageDrawable(getAppIcon(activity, content, app.second)) } catch (e : Exception) { // the button is shown, user asked to select an action viewHolder.img.visibility = View.INVISIBLE From 9a438df3f9f7ea831086463dbfcbe9d295857237 Mon Sep 17 00:00:00 2001 From: Josia Pietsch Date: Fri, 2 Aug 2024 22:46:18 +0200 Subject: [PATCH 009/374] version j-0.0.6 --- .kotlin/sessions/kotlin-compiler-12479629071764159773.salive | 0 README.md | 4 +--- app/build.gradle | 4 ++-- 3 files changed, 3 insertions(+), 5 deletions(-) create mode 100644 .kotlin/sessions/kotlin-compiler-12479629071764159773.salive diff --git a/.kotlin/sessions/kotlin-compiler-12479629071764159773.salive b/.kotlin/sessions/kotlin-compiler-12479629071764159773.salive new file mode 100644 index 0000000..e69de29 diff --git a/README.md b/README.md index 51ae856..3c06b15 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,7 @@ [![][shield-license]][license] - - -# Launcher +# μLauncher This is a fork of [finnmglas's app Launcher][original-repo]. diff --git a/app/build.gradle b/app/build.gradle index 45416cd..359f5a7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -23,8 +23,8 @@ android { applicationId "de.jrpie.android.launcher" minSdkVersion 21 targetSdkVersion 35 - versionCode 17 - versionName "j-0.0.5" + versionCode 18 + versionName "j-0.0.6" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } From 3e4ab2ee97eedda16749f4b6109813b7f809c0d8 Mon Sep 17 00:00:00 2001 From: Josia Pietsch Date: Fri, 2 Aug 2024 23:51:11 +0200 Subject: [PATCH 010/374] updated .gitignore --- .gitignore | 3 ++- ...otlin-compiler-12479629071764159773.salive | 0 app/release/output-metadata.json | 21 ------------------- 3 files changed, 2 insertions(+), 22 deletions(-) delete mode 100644 .kotlin/sessions/kotlin-compiler-12479629071764159773.salive delete mode 100644 app/release/output-metadata.json diff --git a/.gitignore b/.gitignore index 56cc642..ad8dd29 100644 --- a/.gitignore +++ b/.gitignore @@ -15,7 +15,8 @@ bin/ gen/ out/ # Uncomment the following line in case you need and you don't have the release build type files in your app -# release/ +release/ +app/release/ # Gradle files .gradle/ diff --git a/.kotlin/sessions/kotlin-compiler-12479629071764159773.salive b/.kotlin/sessions/kotlin-compiler-12479629071764159773.salive deleted file mode 100644 index e69de29..0000000 diff --git a/app/release/output-metadata.json b/app/release/output-metadata.json deleted file mode 100644 index 7f5bd2d..0000000 --- a/app/release/output-metadata.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "version": 3, - "artifactType": { - "type": "APK", - "kind": "Directory" - }, - "applicationId": "de.jrpie.android.launcher", - "variantName": "release", - "elements": [ - { - "type": "SINGLE", - "filters": [], - "attributes": [], - "versionCode": 16, - "versionName": "j-0.0.4", - "outputFile": "app-release.apk" - } - ], - "elementType": "File", - "minSdkVersionForDexing": 21 -} \ No newline at end of file From 70db5d547610b9f50cd8e631e39fd5116e29bf24 Mon Sep 17 00:00:00 2001 From: Josia Pietsch Date: Fri, 2 Aug 2024 23:51:39 +0200 Subject: [PATCH 011/374] fixed broken Manifest and bug when launching apps --- app/src/main/AndroidManifest.xml | 5 ----- .../jrpie/android/launcher/list/apps/AppsRecyclerAdapter.kt | 5 ++--- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5df0438..f582bd7 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -9,11 +9,6 @@ - - - - - { launchApp(appPackageName, appUser, activity) - val launchIntent: Intent = context.packageManager - .getLaunchIntentForPackage(appPackageName)!! - context.startActivity(launchIntent) + } ListActivity.ListActivityIntention.PICK -> { val returnIntent = Intent() @@ -108,6 +106,7 @@ class AppsRecyclerAdapter(val activity: Activity, } } + // TODO fixme: handle work profile apps @Suppress("SameReturnValue") private fun showOptionsPopup(viewHolder: ViewHolder, appPackageName: String): Boolean { //create the popup menu From 1d19c05e924d22288fa1952b47ce68e400014790 Mon Sep 17 00:00:00 2001 From: Josia Pietsch Date: Fri, 2 Aug 2024 23:51:51 +0200 Subject: [PATCH 012/374] updated .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ad8dd29..5f9584c 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ out/ # Uncomment the following line in case you need and you don't have the release build type files in your app release/ app/release/ +.kotlin/ # Gradle files .gradle/ From 9b145164336746f419bead9a19d0baec226ebc40 Mon Sep 17 00:00:00 2001 From: Josia Pietsch Date: Sat, 3 Aug 2024 00:14:06 +0200 Subject: [PATCH 013/374] version j-0.0.7 --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 359f5a7..f7f349e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -23,8 +23,8 @@ android { applicationId "de.jrpie.android.launcher" minSdkVersion 21 targetSdkVersion 35 - versionCode 18 - versionName "j-0.0.6" + versionCode 19 + versionName "j-0.0.7" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } From bf4298ea5867ad3afab04db4259657d67aa2bfac Mon Sep 17 00:00:00 2001 From: Josia Pietsch Date: Sat, 3 Aug 2024 00:22:18 +0200 Subject: [PATCH 014/374] fix: sort apps alphabetically --- app/src/main/java/de/jrpie/android/launcher/Functions.kt | 1 + .../android/launcher/tutorial/tabs/TutorialFragmentConcept.kt | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) 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 dd70db0..648894d 100644 --- a/app/src/main/java/de/jrpie/android/launcher/Functions.kt +++ b/app/src/main/java/de/jrpie/android/launcher/Functions.kt @@ -394,6 +394,7 @@ fun loadApps(packageManager: PackageManager, context: Context) { loadList.add(app) } } + loadList.sortBy { it.label.toString() } appsList.clear() appsList.addAll(loadList) } diff --git a/app/src/main/java/de/jrpie/android/launcher/tutorial/tabs/TutorialFragmentConcept.kt b/app/src/main/java/de/jrpie/android/launcher/tutorial/tabs/TutorialFragmentConcept.kt index 202bb4c..e35a7c7 100644 --- a/app/src/main/java/de/jrpie/android/launcher/tutorial/tabs/TutorialFragmentConcept.kt +++ b/app/src/main/java/de/jrpie/android/launcher/tutorial/tabs/TutorialFragmentConcept.kt @@ -6,7 +6,6 @@ import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment import de.jrpie.android.launcher.BuildConfig -import de.jrpie.android.launcher.R import de.jrpie.android.launcher.UIObject import de.jrpie.android.launcher.databinding.TutorialConceptBinding /** From 5e841a9106e3af74bba9b6220585eb73d7c007e3 Mon Sep 17 00:00:00 2001 From: Josia Pietsch Date: Mon, 5 Aug 2024 15:08:41 +0200 Subject: [PATCH 015/374] fix: popup menu for work profile apps --- .idea/deploymentTargetSelector.xml | 8 +++ .../de/jrpie/android/launcher/Functions.kt | 56 ++++++++++++++----- .../launcher/list/apps/AppsRecyclerAdapter.kt | 36 +++++------- .../actions/SettingsFragmentActions.kt | 10 +++- .../settings/meta/SettingsFragmentMeta.kt | 17 ++---- app/src/main/res/layout/settings_meta.xml | 7 --- 6 files changed, 77 insertions(+), 57 deletions(-) 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"> -