Skip to content

Commit 66065b7

Browse files
Fix: Fixed a few issues with app draw including icons as well as work profile stuff.
1 parent 86d3326 commit 66065b7

File tree

13 files changed

+263
-117
lines changed

13 files changed

+263
-117
lines changed

app/src/main/AndroidManifest.xml

+9
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,15 @@
1818
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
1919
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
2020
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
21+
22+
<uses-permission
23+
android:name="android.permission.MANAGE_USERS"
24+
tools:ignore="ProtectedPermissions" />
25+
<uses-permission
26+
android:name="android.permission.INTERACT_ACROSS_USERS"
27+
tools:ignore="ProtectedPermissions" />
28+
29+
2130
<uses-permission android:name="${fineLocationPermission}" />
2231
<uses-permission android:name="${coarseLocationPermission}" />
2332

app/src/main/java/com/github/droidworksstudio/common/ContextExtensions.kt

+80-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import android.content.pm.PackageManager
1111
import android.content.res.Configuration
1212
import android.graphics.Bitmap
1313
import android.graphics.drawable.AdaptiveIconDrawable
14+
import android.graphics.drawable.Drawable
1415
import android.net.Uri
1516
import android.os.Build
1617
import android.os.UserHandle
@@ -33,6 +34,7 @@ import androidx.core.graphics.drawable.IconCompat
3334
import androidx.core.graphics.drawable.toBitmap
3435
import androidx.lifecycle.LifecycleObserver
3536
import androidx.lifecycle.LifecycleOwner
37+
import com.github.droidworksstudio.launcher.R
3638
import com.github.droidworksstudio.launcher.data.entities.AppInfo
3739
import com.github.droidworksstudio.launcher.helper.PreferenceHelper
3840
import com.github.droidworksstudio.launcher.ui.activities.LauncherActivity
@@ -193,15 +195,61 @@ fun Context.resetDefaultLauncher() {
193195
fun Context.unInstallApp(appInfo: AppInfo) {
194196
val intent = Intent(Intent.ACTION_DELETE)
195197
intent.data = Uri.parse("package:${appInfo.packageName}")
196-
this.startActivity(intent)
198+
if (appInfo.userHandle > 0) this.showShortToast(getString(R.string.work_permission_message))
199+
else this.startActivity(intent)
197200
}
198201

199202
fun Context.appInfo(appInfo: AppInfo) {
200203
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
201204
intent.data = Uri.fromParts("package", appInfo.packageName, null)
202-
this.startActivity(intent)
205+
// this.test()
206+
if (appInfo.userHandle > 0) this.showShortToast(getString(R.string.work_permission_message))
207+
else this.startActivity(intent)
203208
}
204209

210+
//fun Context.test() {
211+
// // Get the UserManager system service
212+
// val userManager = getSystemService(Context.USER_SERVICE) as? UserManager
213+
// val packageManager = packageManager
214+
//
215+
// // Check if the UserManager is available
216+
// if (userManager == null) {
217+
// Log.e("Error", "UserManager is not available on this device")
218+
// return
219+
// }
220+
//
221+
// // Log available user profiles
222+
// val users = userManager.userProfiles
223+
// Log.d("UserManager", "User profiles: $users")
224+
// // Iterate through users to check for work profiles
225+
// for (userHandle in users) {
226+
// try {
227+
// // Get the UserInfo object for each user
228+
// val userInfo = userManager.getUserInfo(userHandle)
229+
// Log.d("UserManager", "User info for handle $userHandle: ${userInfo.name}")
230+
//
231+
// // Check if this user is a managed (work) profile
232+
// if (userInfo.isManagedProfile) {
233+
// Log.d("WorkProfile", "Work profile found for user: ${userInfo.name}")
234+
//
235+
// // Get installed apps for this work profile
236+
// val appsInWorkProfile = packageManager.getInstalledPackages(PackageManager.GET_META_DATA)
237+
//
238+
// // Log installed apps in the work profile
239+
// for (appInfo in appsInWorkProfile) {
240+
// appInfo.applicationInfo?.let {
241+
// if (it.flags and ApplicationInfo.FLAG_SYSTEM == 0) {
242+
// Log.d("App", "Possible app managing work profile: ${appInfo.packageName}")
243+
// }
244+
// }
245+
// }
246+
// }
247+
// } catch (e: Exception) {
248+
// Log.e("Error", "Failed to get user info for handle $userHandle: ${e.message}")
249+
// }
250+
// }
251+
//}
252+
205253
fun Context.launchApp(appInfo: AppInfo) {
206254
val packageName = appInfo.packageName
207255
val primaryUserHandle = android.os.Process.myUserHandle()
@@ -360,6 +408,36 @@ fun Context.isWorkProfileEnabled(): Boolean {
360408
}
361409
}
362410

411+
fun Context.getAllProfileAppIcons(): Map<Pair<Int?, String?>, Drawable?> {
412+
val launcherApps = this.getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps
413+
val userManager = this.getSystemService(Context.USER_SERVICE) as UserManager
414+
val userHandles = userManager.userProfiles
415+
val appInfoMap = mutableMapOf<Pair<Int?, String?>, Drawable?>()
416+
417+
try {
418+
for (userHandle in userHandles) {
419+
val apps = launcherApps.getActivityList(null, userHandle)
420+
apps.forEach { activityInfo ->
421+
val packageName = activityInfo.applicationInfo.packageName // App's package name
422+
val icon = activityInfo.getBadgedIcon(0) // Drawable for the app's icon
423+
val userHandle = activityInfo.user // UserHandle for the profile the app belongs to
424+
val userId = userHandle.hashCode() // Get the unique integer ID of the UserHandle
425+
426+
// Construct the key as Pair(UserHandle, String)
427+
val key = Pair(userId, packageName)
428+
429+
// Store the pair of UserHandle and label as the key, with the icon as the value
430+
appInfoMap[key] = icon
431+
}
432+
}
433+
} catch (e: Exception) {
434+
e.printStackTrace()
435+
}
436+
437+
return appInfoMap
438+
}
439+
440+
363441
fun Context.hasInternetPermission(): Boolean {
364442
val permission = Manifest.permission.INTERNET
365443
val result = ContextCompat.checkSelfPermission(this, permission)

app/src/main/java/com/github/droidworksstudio/launcher/data/AppDatabase.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import androidx.room.RoomDatabase
66
import com.github.droidworksstudio.launcher.data.dao.AppInfoDAO
77
import com.github.droidworksstudio.launcher.data.entities.AppInfo
88

9-
@Database(entities = [AppInfo::class], version = 1, exportSchema = true)
9+
@Database(entities = [AppInfo::class], version = 1, exportSchema = false)
1010
abstract class AppDatabase : RoomDatabase() {
1111
abstract fun appDao(): AppInfoDAO
1212
}

app/src/main/java/com/github/droidworksstudio/launcher/helper/AppHelper.kt

-1
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,6 @@ class AppHelper @Inject constructor() {
419419
dao.resetAutoIncrement() // Resets the ID counter
420420
}
421421

422-
423422
fun getActionType(actionType: Constants.Swipe): NavOptions {
424423
return when (actionType) {
425424
Constants.Swipe.DoubleTap -> {

app/src/main/java/com/github/droidworksstudio/launcher/repository/AppInfoRepository.kt

+16-2
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,22 @@ class AppInfoRepository @Inject constructor(
175175
launcherApps.getActivityList(null, profile)
176176
.mapNotNull { app ->
177177
val packageName = app.applicationInfo.packageName
178-
val existingApp = getAppByPackageNameWork(packageName)
179-
existingApp
178+
val currentDateTime = LocalDateTime.now()
179+
if (packageName !in existingPackageNames && packageName !in excludedPackageNames) {
180+
AppInfo(
181+
appName = app.label.toString(),
182+
packageName = packageName,
183+
favorite = false,
184+
hidden = false,
185+
lock = false,
186+
createTime = currentDateTime.toString(),
187+
userHandle = userId,
188+
)
189+
} else {
190+
val existingApp = getAppByPackageNameWork(packageName)
191+
existingApp?.let { appList.add(it) }
192+
existingApp
193+
}
180194
}
181195
}
182196
}

app/src/main/java/com/github/droidworksstudio/launcher/ui/bottomsheetdialog/AppInfoBottomSheetFragment.kt

-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ class AppInfoBottomSheetFragment(private val appInfo: AppInfo) : BottomSheetDial
8585
bottomSheetRename.setText(appInfo.appName)
8686
bottomSheetOrder.text = "${appInfo.appOrder}"
8787
}
88-
8988
}
9089

9190

app/src/main/java/com/github/droidworksstudio/launcher/ui/drawer/DrawFragment.kt

+23-2
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ import android.os.Build
66
import android.os.Bundle
77
import android.os.Handler
88
import android.os.Looper
9+
import android.view.Gravity
910
import android.view.LayoutInflater
1011
import android.view.View
1112
import android.view.ViewGroup
13+
import android.widget.LinearLayout
1214
import androidx.annotation.RequiresApi
1315
import androidx.appcompat.widget.SearchView
1416
import androidx.fragment.app.Fragment
@@ -108,10 +110,28 @@ class DrawFragment : Fragment(),
108110

109111
private fun setupRecyclerView() {
110112

113+
// Ensure correct type for layout params
114+
val layoutParams = (binding.drawAdapter.layoutParams as? LinearLayout.LayoutParams)
115+
?: LinearLayout.LayoutParams(
116+
ViewGroup.LayoutParams.MATCH_PARENT,
117+
ViewGroup.LayoutParams.WRAP_CONTENT
118+
)
119+
120+
// Set gravity to align RecyclerView to the bottom
121+
layoutParams.gravity = when (preferenceHelper.homeAppAlignment) {
122+
Gravity.START -> Gravity.START or Gravity.BOTTOM
123+
Gravity.CENTER -> Gravity.CENTER or Gravity.BOTTOM
124+
Gravity.END -> Gravity.END or Gravity.BOTTOM
125+
else -> Gravity.BOTTOM
126+
}
127+
128+
// Apply configurations to RecyclerView
111129
binding.drawAdapter.apply {
112130
adapter = drawAdapter
113-
layoutManager = StaggeredGridLayoutManager(1, StaggeredGridLayoutManager.VERTICAL)
131+
this.layoutParams = layoutParams
114132
setHasFixedSize(false)
133+
layoutManager = StaggeredGridLayoutManager(1, StaggeredGridLayoutManager.VERTICAL)
134+
isNestedScrollingEnabled = false
115135
}
116136
}
117137

@@ -173,7 +193,8 @@ class DrawFragment : Fragment(),
173193
private fun observeSwipeTouchListener() {
174194
binding.apply {
175195
mainView.setOnTouchListener(getSwipeGestureListener(context))
176-
drawAdapter.setOnTouchListener(getSwipeGestureListener(context))
196+
touchArea.setOnTouchListener(getSwipeGestureListener(context))
197+
appListTouchArea.setOnTouchListener(getSwipeGestureListener(context))
177198
}
178199
}
179200

app/src/main/java/com/github/droidworksstudio/launcher/ui/drawer/DrawViewHolder.kt

+54-47
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.github.droidworksstudio.launcher.ui.drawer
22

3-
import android.content.pm.PackageManager
43
import android.graphics.drawable.Drawable
54
import android.view.Gravity
65
import android.view.View
@@ -9,6 +8,7 @@ import androidx.core.content.ContextCompat
98
import androidx.recyclerview.widget.RecyclerView
109
import com.github.droidworksstudio.common.ColorIconsExtensions
1110
import com.github.droidworksstudio.common.dpToPx
11+
import com.github.droidworksstudio.common.getAllProfileAppIcons
1212
import com.github.droidworksstudio.launcher.R
1313
import com.github.droidworksstudio.launcher.data.entities.AppInfo
1414
import com.github.droidworksstudio.launcher.databinding.ItemDrawBinding
@@ -20,7 +20,7 @@ class DrawViewHolder(
2020
private val binding: ItemDrawBinding,
2121
private val onAppClickedListener: OnItemClickedListener.OnAppsClickedListener,
2222
private val onAppLongClickedListener: OnItemClickedListener.OnAppLongClickedListener,
23-
private val preferenceHelper: PreferenceHelper
23+
private val preferenceHelper: PreferenceHelper,
2424
) :
2525

2626
RecyclerView.ViewHolder(binding.root) {
@@ -43,48 +43,57 @@ class DrawViewHolder(
4343
appDrawName.gravity = preferenceHelper.homeAppAlignment
4444

4545
if (preferenceHelper.showAppIcon) {
46-
val pm: PackageManager = binding.root.context.packageManager
47-
val appIcon = pm.getApplicationIcon(appInfo.packageName)
48-
val appIconSize = (preferenceHelper.appTextSize * if (preferenceHelper.iconPack == Constants.IconPacks.System) 2f else 1.1f).toInt()
49-
50-
val layoutParams = LinearLayoutCompat.LayoutParams(appIconSize, appIconSize)
51-
val appNewIcon: Drawable? = if (preferenceHelper.iconPack == Constants.IconPacks.EasyDots) {
52-
val newIcon = ContextCompat.getDrawable(itemView.context, R.drawable.app_easy_dot_icon)!!
53-
val bitmap = ColorIconsExtensions.drawableToBitmap(appIcon)
54-
val dominantColor = ColorIconsExtensions.getDominantColor(bitmap)
55-
ColorIconsExtensions.recolorDrawable(newIcon, dominantColor)
56-
} else if (preferenceHelper.iconPack == Constants.IconPacks.NiagaraDots) {
57-
val newIcon = ContextCompat.getDrawable(itemView.context, R.drawable.app_niagara_dot_icon)!!
58-
val bitmap = ColorIconsExtensions.drawableToBitmap(appIcon)
59-
val dominantColor = ColorIconsExtensions.getDominantColor(bitmap)
60-
ColorIconsExtensions.recolorDrawable(newIcon, dominantColor)
61-
} else {
62-
null
63-
}
64-
65-
appDrawIcon.layoutParams = layoutParams
66-
appDrawIcon.setImageDrawable(appNewIcon ?: appIcon)
67-
appDrawIcon.visibility = View.VISIBLE
68-
69-
val parentLayout = appDrawName.parent as LinearLayoutCompat
70-
parentLayout.orientation = LinearLayoutCompat.HORIZONTAL
71-
parentLayout.removeAllViews()
72-
73-
when (preferenceHelper.homeAppAlignment) {
74-
Gravity.START -> {
75-
layoutParams.marginEnd = 10.dpToPx()
76-
parentLayout.addView(appDrawIcon)
77-
parentLayout.addView(appDrawName)
78-
}
79-
80-
Gravity.END -> {
81-
layoutParams.marginStart = 10.dpToPx()
82-
parentLayout.addView(appDrawName)
83-
parentLayout.addView(appDrawIcon)
84-
}
85-
86-
else -> {
87-
appDrawIcon.visibility = View.GONE
46+
val appInfoMap = root.context.getAllProfileAppIcons()
47+
appInfoMap.forEach { (key, icon) ->
48+
val userHandle: Int? = key.first
49+
val packageName: String? = key.second
50+
if (appInfo.packageName == packageName && appInfo.userHandle == userHandle) {
51+
val easyDot = ContextCompat.getDrawable(itemView.context, R.drawable.app_easy_dot_icon)!!
52+
val appIcon = icon
53+
val nonNullDrawable: Drawable = appIcon ?: easyDot
54+
55+
val appIconSize = (preferenceHelper.appTextSize * if (preferenceHelper.iconPack == Constants.IconPacks.System) 2f else 1.1f).toInt()
56+
57+
val layoutParams = LinearLayoutCompat.LayoutParams(appIconSize, appIconSize)
58+
val appNewIcon: Drawable? = if (preferenceHelper.iconPack == Constants.IconPacks.EasyDots) {
59+
val newIcon = ContextCompat.getDrawable(itemView.context, R.drawable.app_easy_dot_icon)!!
60+
val bitmap = ColorIconsExtensions.drawableToBitmap(nonNullDrawable)
61+
val dominantColor = ColorIconsExtensions.getDominantColor(bitmap)
62+
ColorIconsExtensions.recolorDrawable(newIcon, dominantColor)
63+
} else if (preferenceHelper.iconPack == Constants.IconPacks.NiagaraDots) {
64+
val newIcon = ContextCompat.getDrawable(itemView.context, R.drawable.app_niagara_dot_icon)!!
65+
val bitmap = ColorIconsExtensions.drawableToBitmap(nonNullDrawable)
66+
val dominantColor = ColorIconsExtensions.getDominantColor(bitmap)
67+
ColorIconsExtensions.recolorDrawable(newIcon, dominantColor)
68+
} else {
69+
null
70+
}
71+
72+
appDrawIcon.layoutParams = layoutParams
73+
appDrawIcon.setImageDrawable(appNewIcon ?: nonNullDrawable)
74+
appDrawIcon.visibility = View.VISIBLE
75+
76+
val parentLayout = appDrawName.parent as LinearLayoutCompat
77+
parentLayout.orientation = LinearLayoutCompat.HORIZONTAL
78+
parentLayout.removeAllViews()
79+
80+
when (preferenceHelper.homeAppAlignment) {
81+
Gravity.START -> {
82+
layoutParams.marginEnd = 10.dpToPx()
83+
parentLayout.addView(appDrawIcon)
84+
parentLayout.addView(appDrawName)
85+
}
86+
87+
Gravity.END -> {
88+
layoutParams.marginStart = 10.dpToPx()
89+
parentLayout.addView(appDrawName)
90+
parentLayout.addView(appDrawIcon)
91+
}
92+
93+
else -> {
94+
parentLayout.addView(appDrawName)
95+
}
96+
}
8897
}
8998
}
9099
} else {
@@ -97,9 +106,7 @@ class DrawViewHolder(
97106
}
98107

99108
itemView.setOnLongClickListener {
100-
if (appInfo.userHandle <= 0) {
101-
onAppLongClickedListener.onAppLongClicked(appInfo)
102-
}
109+
onAppLongClickedListener.onAppLongClicked(appInfo)
103110
true
104111
}
105112
}

0 commit comments

Comments
 (0)