mirror of
https://github.com/jrpie/Launcher.git
synced 2025-02-22 22:11:27 +01:00
chore: split AppInfo into AppInfo and DetailedAppInfo
This commit is contained in:
parent
95e2f82736
commit
e4b1bccf85
10 changed files with 130 additions and 123 deletions
|
@ -6,7 +6,6 @@ import android.app.role.RoleManager
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.content.pm.LauncherActivityInfo
|
||||
import android.content.pm.LauncherApps
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.ColorMatrix
|
||||
|
@ -18,7 +17,6 @@ import android.os.Bundle
|
|||
import android.os.UserHandle
|
||||
import android.os.UserManager
|
||||
import android.provider.Settings
|
||||
import android.util.DisplayMetrics
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.view.animation.AlphaAnimation
|
||||
|
@ -26,25 +24,20 @@ import android.view.animation.Animation
|
|||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.ImageView
|
||||
import de.jrpie.android.launcher.actions.Action
|
||||
import de.jrpie.android.launcher.actions.AppInfo
|
||||
import de.jrpie.android.launcher.actions.Gesture
|
||||
import de.jrpie.android.launcher.apps.AppInfo
|
||||
import de.jrpie.android.launcher.apps.DetailedAppInfo
|
||||
import de.jrpie.android.launcher.ui.list.apps.AppsRecyclerAdapter
|
||||
import de.jrpie.android.launcher.ui.tutorial.TutorialActivity
|
||||
|
||||
|
||||
const val INVALID_USER = -1
|
||||
|
||||
/* Objects used by multiple activities */
|
||||
val appsList: MutableList<AppInfo> = ArrayList()
|
||||
|
||||
/* Variables containing settings */
|
||||
val displayMetrics = DisplayMetrics()
|
||||
val appsList: MutableList<DetailedAppInfo> = ArrayList()
|
||||
|
||||
/* REQUEST CODES */
|
||||
|
||||
const val REQUEST_CHOOSE_APP = 1
|
||||
const val REQUEST_CHOOSE_APP_FROM_FAVORITES = 2
|
||||
const val REQUEST_UNINSTALL = 3
|
||||
const val REQUEST_UNINSTALL = 2
|
||||
|
||||
const val REQUEST_SET_DEFAULT_HOME = 42
|
||||
|
||||
|
@ -109,16 +102,6 @@ fun getUserFromId(user: Int?, context: Context): UserHandle? {
|
|||
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(appInfo: AppInfo, activity: Activity) {
|
||||
val packageName = appInfo.packageName.toString()
|
||||
|
@ -154,7 +137,7 @@ fun openAppSettings(
|
|||
opts: Bundle? = null
|
||||
) {
|
||||
val launcherApps = context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps
|
||||
getLauncherActivityInfo(appInfo.packageName.toString(), appInfo.user, context)?.let { app ->
|
||||
appInfo.getLauncherActivityInfo(context)?.let { app ->
|
||||
launcherApps.startAppDetailsActivity(app.componentName, app.user, sourceBounds, opts)
|
||||
}
|
||||
}
|
||||
|
@ -169,7 +152,7 @@ fun openTutorial(context: Context) {
|
|||
* as it caches all the apps and allows for fast access to the data.
|
||||
*/
|
||||
fun loadApps(packageManager: PackageManager, context: Context) {
|
||||
val loadList = mutableListOf<AppInfo>()
|
||||
val loadList = mutableListOf<DetailedAppInfo>()
|
||||
|
||||
val launcherApps = context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps
|
||||
val userManager = context.getSystemService(Service.USER_SERVICE) as UserManager
|
||||
|
@ -178,14 +161,14 @@ fun loadApps(packageManager: PackageManager, context: Context) {
|
|||
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()
|
||||
app.isSystemApp =
|
||||
val app = AppInfo(activityInfo.applicationInfo.packageName, user.hashCode())
|
||||
val detailedAppInfo = DetailedAppInfo(
|
||||
app,
|
||||
activityInfo.label,
|
||||
activityInfo.getBadgedIcon(0),
|
||||
activityInfo.applicationInfo.flags.and(ApplicationInfo.FLAG_SYSTEM) != 0
|
||||
loadList.add(app)
|
||||
)
|
||||
loadList.add(detailedAppInfo)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -197,11 +180,13 @@ fun loadApps(packageManager: PackageManager, context: Context) {
|
|||
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)
|
||||
val app = AppInfo(ri.activityInfo.packageName, AppInfo.INVALID_USER)
|
||||
val detailedAppInfo = DetailedAppInfo(
|
||||
app,
|
||||
ri.loadLabel(packageManager),
|
||||
ri.activityInfo.loadIcon(packageManager)
|
||||
)
|
||||
loadList.add(detailedAppInfo)
|
||||
}
|
||||
}
|
||||
loadList.sortBy { it.label.toString() }
|
||||
|
|
|
@ -7,8 +7,9 @@ import android.content.SharedPreferences.Editor
|
|||
import android.graphics.Rect
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.widget.Toast
|
||||
import de.jrpie.android.launcher.INVALID_USER
|
||||
import de.jrpie.android.launcher.R
|
||||
import de.jrpie.android.launcher.apps.AppInfo
|
||||
import de.jrpie.android.launcher.apps.AppInfo.Companion.INVALID_USER
|
||||
import de.jrpie.android.launcher.preferences.LauncherPreferences
|
||||
|
||||
interface Action {
|
||||
|
@ -29,7 +30,7 @@ interface Action {
|
|||
return LauncherAction.byId(id)
|
||||
}
|
||||
|
||||
return AppAction(AppInfo(id, user))
|
||||
return AppAction(AppInfo(id, user ?: INVALID_USER))
|
||||
}
|
||||
|
||||
fun forGesture(gesture: Gesture): Action? {
|
||||
|
|
|
@ -8,21 +8,22 @@ import android.content.SharedPreferences
|
|||
import android.content.pm.LauncherApps
|
||||
import android.graphics.Rect
|
||||
import android.graphics.drawable.Drawable
|
||||
import de.jrpie.android.launcher.INVALID_USER
|
||||
import de.jrpie.android.launcher.R
|
||||
import de.jrpie.android.launcher.apps.AppInfo
|
||||
import de.jrpie.android.launcher.apps.AppInfo.Companion.INVALID_USER
|
||||
import de.jrpie.android.launcher.apps.DetailedAppInfo
|
||||
import de.jrpie.android.launcher.getIntent
|
||||
import de.jrpie.android.launcher.getLauncherActivityInfo
|
||||
import de.jrpie.android.launcher.openAppSettings
|
||||
|
||||
class AppAction(private var appInfo: AppInfo) : Action {
|
||||
|
||||
|
||||
override fun invoke(context: Context, rect: Rect?): Boolean {
|
||||
val packageName = appInfo.packageName.toString()
|
||||
val user = appInfo.user
|
||||
if (user != null && user != INVALID_USER) {
|
||||
if (appInfo.user != INVALID_USER) {
|
||||
val launcherApps =
|
||||
context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps
|
||||
getLauncherActivityInfo(packageName, user, context)?.let { app ->
|
||||
appInfo.getLauncherActivityInfo(context)?.let { app ->
|
||||
launcherApps.startMainActivity(app.componentName, app.user, rect, null)
|
||||
return true
|
||||
}
|
||||
|
@ -35,7 +36,9 @@ class AppAction(private var appInfo: AppInfo) : Action {
|
|||
return true
|
||||
}
|
||||
|
||||
if (AppInfo(packageName).isInstalled(context)) {
|
||||
|
||||
/* check if app is installed */
|
||||
if (isAvailable(context)) {
|
||||
AlertDialog.Builder(
|
||||
context,
|
||||
R.style.AlertDialogCustom
|
||||
|
@ -54,21 +57,16 @@ class AppAction(private var appInfo: AppInfo) : Action {
|
|||
}
|
||||
|
||||
override fun label(context: Context): String {
|
||||
return appInfo.label.toString()
|
||||
return DetailedAppInfo.fromAppInfo(appInfo, context)?.label.toString()
|
||||
}
|
||||
|
||||
override fun getIcon(context: Context): Drawable? {
|
||||
var icon: Drawable? = null
|
||||
try {
|
||||
icon = appInfo.getAppIcon(context)
|
||||
} catch (e: Exception) {
|
||||
// probably the app was uninstalled
|
||||
}
|
||||
return icon
|
||||
return DetailedAppInfo.fromAppInfo(appInfo, context)?.icon
|
||||
}
|
||||
|
||||
override fun isAvailable(context: Context): Boolean {
|
||||
return appInfo.isInstalled(context)
|
||||
// check if app is installed
|
||||
return DetailedAppInfo.fromAppInfo(appInfo, context) != null;
|
||||
}
|
||||
|
||||
override fun bindToGesture(editor: SharedPreferences.Editor, id: String) {
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
package de.jrpie.android.launcher.actions
|
||||
|
||||
import android.app.Service
|
||||
import android.content.Context
|
||||
import android.content.pm.LauncherApps
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.drawable.Drawable
|
||||
import de.jrpie.android.launcher.INVALID_USER
|
||||
import de.jrpie.android.launcher.getUserFromId
|
||||
|
||||
/**
|
||||
* Stores information used to create [AppsRecyclerAdapter] rows.
|
||||
*
|
||||
* Represents an app installed on the users device.
|
||||
*/
|
||||
class AppInfo(var packageName: CharSequence? = null, var user: Int? = null) {
|
||||
var label: CharSequence? = null
|
||||
var icon: Drawable? = null
|
||||
var isSystemApp: Boolean = false
|
||||
|
||||
fun getAppIcon(context: Context): Drawable {
|
||||
if (user != null && user != INVALID_USER) {
|
||||
val launcherApps =
|
||||
context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps
|
||||
getUserFromId(user, context)?.let { userHandle ->
|
||||
launcherApps.getActivityList(packageName.toString(), userHandle).firstOrNull()
|
||||
?.let { app ->
|
||||
return app.getBadgedIcon(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
return context.packageManager.getApplicationIcon(packageName.toString())
|
||||
}
|
||||
|
||||
fun isInstalled(context: Context): Boolean {
|
||||
/* TODO: this should also check the user */
|
||||
try {
|
||||
context.packageManager.getPackageInfo(
|
||||
packageName.toString(),
|
||||
PackageManager.GET_ACTIVITIES
|
||||
)
|
||||
return true
|
||||
} catch (_: PackageManager.NameNotFoundException) {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -9,8 +9,8 @@ import android.media.AudioManager
|
|||
import android.os.SystemClock
|
||||
import android.view.KeyEvent
|
||||
import android.widget.Toast
|
||||
import de.jrpie.android.launcher.INVALID_USER
|
||||
import de.jrpie.android.launcher.R
|
||||
import de.jrpie.android.launcher.apps.AppInfo.Companion.INVALID_USER
|
||||
import de.jrpie.android.launcher.ui.list.ListActivity
|
||||
import de.jrpie.android.launcher.ui.settings.SettingsActivity
|
||||
|
||||
|
|
40
app/src/main/java/de/jrpie/android/launcher/apps/AppInfo.kt
Normal file
40
app/src/main/java/de/jrpie/android/launcher/apps/AppInfo.kt
Normal file
|
@ -0,0 +1,40 @@
|
|||
package de.jrpie.android.launcher.apps
|
||||
|
||||
import android.app.Service
|
||||
import android.content.Context
|
||||
import android.content.pm.LauncherActivityInfo
|
||||
import android.content.pm.LauncherApps
|
||||
import de.jrpie.android.launcher.getUserFromId
|
||||
|
||||
/**
|
||||
* Represents an app installed on the users device.
|
||||
* Contains the minimal amount of data required to identify the app.
|
||||
*/
|
||||
class AppInfo(val packageName: CharSequence, val user: Int = INVALID_USER) {
|
||||
|
||||
fun serialize(): String {
|
||||
val u = user
|
||||
return "$packageName;$u"
|
||||
}
|
||||
|
||||
fun getLauncherActivityInfo(
|
||||
context: Context
|
||||
): LauncherActivityInfo? {
|
||||
val launcherApps = context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps
|
||||
return getUserFromId(user, context)?.let { userHandle ->
|
||||
launcherApps.getActivityList(packageName.toString(), userHandle).firstOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
const val INVALID_USER = -1
|
||||
|
||||
fun deserialize(serialized: String): AppInfo {
|
||||
val values = serialized.split(";")
|
||||
val packageName = values[0]
|
||||
val user = Integer.valueOf(values[1])
|
||||
return AppInfo(packageName, user)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package de.jrpie.android.launcher.apps
|
||||
|
||||
import android.content.Context
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.content.pm.LauncherActivityInfo
|
||||
import android.graphics.drawable.Drawable
|
||||
|
||||
/**
|
||||
* Stores information used to create [AppsRecyclerAdapter] rows.
|
||||
*/
|
||||
class DetailedAppInfo(
|
||||
val app: AppInfo,
|
||||
val label: CharSequence,
|
||||
val icon: Drawable,
|
||||
val isSystemApp: Boolean = false,
|
||||
) {
|
||||
|
||||
constructor(activityInfo: LauncherActivityInfo) : this(
|
||||
AppInfo(activityInfo.applicationInfo.packageName, activityInfo.user.hashCode()),
|
||||
activityInfo.label,
|
||||
activityInfo.getBadgedIcon(0),
|
||||
activityInfo.applicationInfo.flags.and(ApplicationInfo.FLAG_SYSTEM) != 0
|
||||
)
|
||||
|
||||
companion object {
|
||||
fun fromAppInfo(appInfo: AppInfo, context: Context): DetailedAppInfo? {
|
||||
return appInfo.getLauncherActivityInfo(context)?.let { DetailedAppInfo(it) }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,7 +15,8 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import de.jrpie.android.launcher.R
|
||||
import de.jrpie.android.launcher.REQUEST_CHOOSE_APP
|
||||
import de.jrpie.android.launcher.actions.AppAction
|
||||
import de.jrpie.android.launcher.actions.AppInfo
|
||||
import de.jrpie.android.launcher.apps.AppInfo
|
||||
import de.jrpie.android.launcher.apps.DetailedAppInfo
|
||||
import de.jrpie.android.launcher.appsList
|
||||
import de.jrpie.android.launcher.loadApps
|
||||
import de.jrpie.android.launcher.openAppSettings
|
||||
|
@ -42,7 +43,7 @@ class AppsRecyclerAdapter(
|
|||
) :
|
||||
RecyclerView.Adapter<AppsRecyclerAdapter.ViewHolder>() {
|
||||
|
||||
private val appsListDisplayed: MutableList<AppInfo>
|
||||
private val appsListDisplayed: MutableList<DetailedAppInfo>
|
||||
|
||||
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView),
|
||||
View.OnClickListener {
|
||||
|
@ -62,10 +63,7 @@ class AppsRecyclerAdapter(
|
|||
|
||||
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
|
||||
|
||||
viewHolder.textView.text = appLabel
|
||||
viewHolder.img.setImageDrawable(appIcon)
|
||||
|
@ -79,17 +77,13 @@ class AppsRecyclerAdapter(
|
|||
viewHolder.textView.setOnLongClickListener {
|
||||
showOptionsPopup(
|
||||
viewHolder,
|
||||
appPackageName,
|
||||
appUser,
|
||||
isSystemApp
|
||||
appsListDisplayed[i]
|
||||
)
|
||||
}
|
||||
viewHolder.img.setOnLongClickListener {
|
||||
showOptionsPopup(
|
||||
viewHolder,
|
||||
appPackageName,
|
||||
appUser,
|
||||
isSystemApp
|
||||
appsListDisplayed[i]
|
||||
)
|
||||
}
|
||||
// ensure onClicks are actually caught
|
||||
|
@ -101,28 +95,26 @@ class AppsRecyclerAdapter(
|
|||
@Suppress("SameReturnValue")
|
||||
private fun showOptionsPopup(
|
||||
viewHolder: ViewHolder,
|
||||
appPackageName: String,
|
||||
user: Int?,
|
||||
isSystemApp: Boolean
|
||||
appInfo: DetailedAppInfo
|
||||
): Boolean {
|
||||
//create the popup menu
|
||||
|
||||
val popup = PopupMenu(activity, viewHolder.img)
|
||||
popup.inflate(R.menu.menu_app)
|
||||
|
||||
if (isSystemApp) {
|
||||
if (appInfo.isSystemApp) {
|
||||
popup.menu.findItem(R.id.app_menu_delete).setVisible(false)
|
||||
}
|
||||
|
||||
popup.setOnMenuItemClickListener {
|
||||
when (it.itemId) {
|
||||
R.id.app_menu_delete -> {
|
||||
uninstallApp(AppInfo(appPackageName, user), activity)
|
||||
uninstallApp(appInfo.app, activity)
|
||||
true
|
||||
}
|
||||
|
||||
R.id.app_menu_info -> {
|
||||
openAppSettings(AppInfo(appPackageName, user), activity)
|
||||
openAppSettings(appInfo.app, activity)
|
||||
true
|
||||
}
|
||||
|
||||
|
@ -164,12 +156,12 @@ class AppsRecyclerAdapter(
|
|||
val appInfo = appsListDisplayed[pos]
|
||||
when (intention) {
|
||||
ListActivity.ListActivityIntention.VIEW -> {
|
||||
AppAction(appInfo).invoke(activity, rect)
|
||||
AppAction(appInfo.app).invoke(activity, rect)
|
||||
}
|
||||
|
||||
ListActivity.ListActivityIntention.PICK -> {
|
||||
val returnIntent = Intent()
|
||||
AppAction(appInfo).writeToIntent(returnIntent)
|
||||
AppAction(appInfo.app).writeToIntent(returnIntent)
|
||||
returnIntent.putExtra("forGesture", forGesture)
|
||||
activity.setResult(REQUEST_CHOOSE_APP, returnIntent)
|
||||
activity.finish()
|
||||
|
@ -198,7 +190,7 @@ class AppsRecyclerAdapter(
|
|||
if (text.isEmpty()) {
|
||||
appsListDisplayed.addAll(appsList)
|
||||
} else {
|
||||
val appsSecondary: MutableList<AppInfo> = ArrayList()
|
||||
val appsSecondary: MutableList<DetailedAppInfo> = ArrayList()
|
||||
val normalizedText: String = normalize(text)
|
||||
for (item in appsList) {
|
||||
val itemLabel: String = normalize(item.label.toString())
|
||||
|
@ -216,7 +208,7 @@ class AppsRecyclerAdapter(
|
|||
&& LauncherPreferences.functionality().searchAutoLaunch()
|
||||
) {
|
||||
val info = appsListDisplayed[0]
|
||||
AppAction(info).invoke(activity)
|
||||
AppAction(info.app).invoke(activity)
|
||||
|
||||
val inputMethodManager =
|
||||
activity.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
|
|
5
app/src/main/res/drawable/baseline_favorite_24.xml
Normal file
5
app/src/main/res/drawable/baseline_favorite_24.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#FFFFFF" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M12,17.27L18.18,21l-1.64,-7.03L22,9.24l-7.19,-0.61L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21z"/>
|
||||
|
||||
</vector>
|
|
@ -0,0 +1,5 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#FFFFFF" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M22,9.24l-7.19,-0.62L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21 12,17.27 18.18,21l-1.63,-7.03L22,9.24zM12,15.4l-3.76,2.27 1,-4.28 -3.32,-2.88 4.38,-0.38L12,6.1l1.71,4.04 4.38,0.38 -3.32,2.88 1,4.28L12,15.4z"/>
|
||||
|
||||
</vector>
|
Loading…
Add table
Reference in a new issue