diff --git a/app/src/main/java/com/github/droidworksstudio/ktx/ContextExtensions.kt b/app/src/main/java/com/github/droidworksstudio/ktx/ContextExtensions.kt index bec592b..1acea18 100644 --- a/app/src/main/java/com/github/droidworksstudio/ktx/ContextExtensions.kt +++ b/app/src/main/java/com/github/droidworksstudio/ktx/ContextExtensions.kt @@ -14,6 +14,7 @@ import android.graphics.drawable.AdaptiveIconDrawable import android.net.Uri import android.os.Build import android.os.UserHandle +import android.os.UserManager import android.provider.AlarmClock import android.provider.CalendarContract import android.provider.Settings @@ -297,6 +298,16 @@ fun Context.searchCustomSearchEngine(searchQuery: String? = null): Boolean { return true } +fun Context.isWorkProfileEnabled(): Boolean { + val userManager = getSystemService(Context.USER_SERVICE) as? UserManager + return if (userManager != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val profiles = userManager.userProfiles + profiles.size > 1 + } else { + false + } +} + fun Context.backupSharedPreferences(backupFileName: String) { val sharedPreferences: SharedPreferences = this.getSharedPreferences(Constants.PREFS_FILENAME, 0) diff --git a/app/src/main/java/com/github/droidworksstudio/launcher/data/dao/AppInfoDAO.kt b/app/src/main/java/com/github/droidworksstudio/launcher/data/dao/AppInfoDAO.kt index f0a0753..d96ba90 100644 --- a/app/src/main/java/com/github/droidworksstudio/launcher/data/dao/AppInfoDAO.kt +++ b/app/src/main/java/com/github/droidworksstudio/launcher/data/dao/AppInfoDAO.kt @@ -17,7 +17,7 @@ interface AppInfoDAO { suspend fun update(app: AppInfo) @Delete - suspend fun delete(app: AppInfo) + fun delete(app: AppInfo) @Query("SELECT * FROM app ORDER BY app_name COLLATE NOCASE ASC") fun getAllApps(): List @@ -73,9 +73,12 @@ interface AppInfoDAO { @Query("SELECT * FROM app WHERE is_favorite = 1") fun getFavoriteAppInfo(): List - @Query("SELECT * FROM app WHERE package_name = :packageName") + @Query("SELECT * FROM app WHERE package_name = :packageName AND is_work = 0") suspend fun getAppByPackageName(packageName: String): AppInfo? + @Query("SELECT * FROM app WHERE package_name = :packageName AND is_work = 1") + suspend fun getAppByPackageNameWork(packageName: String): AppInfo? + private fun logUpdate(message: String, appInfo: AppInfo) { // You can replace this with a logging library like Timber for more advanced logging capabilities. Log.d( diff --git a/app/src/main/java/com/github/droidworksstudio/launcher/data/entities/AppInfo.kt b/app/src/main/java/com/github/droidworksstudio/launcher/data/entities/AppInfo.kt index 5eb9095..45d2336 100644 --- a/app/src/main/java/com/github/droidworksstudio/launcher/data/entities/AppInfo.kt +++ b/app/src/main/java/com/github/droidworksstudio/launcher/data/entities/AppInfo.kt @@ -26,8 +26,11 @@ data class AppInfo( @ColumnInfo(name = "is_lock") var lock: Boolean, + @ColumnInfo(name = "is_work") + var work: Boolean, + @ColumnInfo(name = "create_time") - var createTime: String = "", + var createTime: String, @ColumnInfo(name = "app_order") var appOrder: Int = -1 diff --git a/app/src/main/java/com/github/droidworksstudio/launcher/listener/OnSwipeTouchListener.kt b/app/src/main/java/com/github/droidworksstudio/launcher/listener/OnSwipeTouchListener.kt index c61c018..0bafdda 100644 --- a/app/src/main/java/com/github/droidworksstudio/launcher/listener/OnSwipeTouchListener.kt +++ b/app/src/main/java/com/github/droidworksstudio/launcher/listener/OnSwipeTouchListener.kt @@ -85,8 +85,8 @@ internal open class OnSwipeTouchListener(c: Context?) : OnTouchListener { if (diffY < 0) onSwipeUp() else onSwipeDown() } } - } catch (exception: Exception) { - exception.printStackTrace() + } catch (exception: NullPointerException) { + return false } return false } diff --git a/app/src/main/java/com/github/droidworksstudio/launcher/repository/AppInfoRepository.kt b/app/src/main/java/com/github/droidworksstudio/launcher/repository/AppInfoRepository.kt index b8c62ec..a8ff0c3 100644 --- a/app/src/main/java/com/github/droidworksstudio/launcher/repository/AppInfoRepository.kt +++ b/app/src/main/java/com/github/droidworksstudio/launcher/repository/AppInfoRepository.kt @@ -3,8 +3,11 @@ package com.github.droidworksstudio.launcher.repository import android.content.Context import android.content.pm.LauncherApps import android.content.pm.PackageManager +import android.os.Build +import android.os.UserHandle import android.os.UserManager import android.util.Log +import androidx.annotation.RequiresApi import com.github.droidworksstudio.launcher.Constants import com.github.droidworksstudio.launcher.data.dao.AppInfoDAO import com.github.droidworksstudio.launcher.data.entities.AppInfo @@ -12,11 +15,13 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.withContext +import java.lang.reflect.Method +import java.time.LocalDateTime import javax.inject.Inject class AppInfoRepository @Inject constructor( - private val appDao: AppInfoDAO + private val appDao: AppInfoDAO, ) { @Inject @@ -98,7 +103,9 @@ class AppInfoRepository @Inject constructor( packages } - suspend fun initInstalledAppInfo(context: Context): List = withContext(Dispatchers.IO) { + @RequiresApi(Build.VERSION_CODES.O) + suspend fun initInstalledAppInfo(context: Context): List = + withContext(Dispatchers.IO) { val appList: MutableList = mutableListOf() val allApps = appDao.getAllAppsFlow().firstOrNull() @@ -109,29 +116,69 @@ class AppInfoRepository @Inject constructor( val launcherApps = context.getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps - val excludedPackageNames = mutableListOf(Constants.PACKAGE_NAME,Constants.PACKAGE_NAME_DEBUG) + val excludedPackageNames = + mutableListOf(Constants.PACKAGE_NAME, Constants.PACKAGE_NAME_DEBUG) + + val getIdentifierMethod: Method = + UserHandle::class.java.getDeclaredMethod("getIdentifier") val newAppList: List = userManager.userProfiles .flatMap { profile -> - launcherApps.getActivityList(null, profile) - .mapNotNull { app -> - val packageName = app.applicationInfo.packageName - if (packageName !in existingPackageNames && packageName !in excludedPackageNames) { - AppInfo( - appName = app.label.toString(), - packageName = packageName, - favorite = false, - hidden = false, - lock = false - ) - } else { - val existingApp = getAppByPackageName(packageName) - existingApp?.let { appList.add(it) } - existingApp - } + // Invoke the getIdentifier method on the UserHandle instance + val userId = getIdentifierMethod.invoke(profile) as Int + + when (userId) { + 0 -> { + // Handle the case when profile is UserHandle{0} + launcherApps.getActivityList(null, profile) + .mapNotNull { app -> + val packageName = app.applicationInfo.packageName + val currentDateTime = LocalDateTime.now() + if (packageName !in existingPackageNames && packageName !in excludedPackageNames) { + AppInfo( + appName = app.label.toString(), + packageName = packageName, + favorite = false, + hidden = false, + lock = false, + createTime = currentDateTime.toString(), + work = false, + ) + } else { + val existingApp = getAppByPackageName(packageName) + existingApp?.let { appList.add(it) } + existingApp + } + } } + + else -> { + // Handle other profiles + launcherApps.getActivityList(null, profile) + .mapNotNull { app -> + val packageName = app.applicationInfo.packageName + val currentDateTime = LocalDateTime.now() + if (packageName !in existingPackageNames && packageName !in excludedPackageNames) { + AppInfo( + appName = app.label.toString(), + packageName = packageName, + favorite = false, + hidden = false, + lock = false, + createTime = currentDateTime.toString(), + work = true, + ) + } else { + val existingApp = getAppByPackageNameWork(packageName) + existingApp?.let { appList.add(it) } + existingApp + } + } + } + } } + appDao.insertAll(newAppList.sortedBy { it.appName }) Log.d("Tag", "State: ${newAppList.sortedBy { it.appName }}") @@ -142,6 +189,7 @@ class AppInfoRepository @Inject constructor( appList } + @RequiresApi(Build.VERSION_CODES.R) suspend fun compareInstalledApp(): List = withContext(Dispatchers.IO) { val installedPackages = getInstalledPackages() val uninstalledApps = mutableListOf() @@ -176,4 +224,8 @@ class AppInfoRepository @Inject constructor( private suspend fun getAppByPackageName(packageName: String): AppInfo? { return appDao.getAppByPackageName(packageName) } + + private suspend fun getAppByPackageNameWork(packageName: String): AppInfo? { + return appDao.getAppByPackageNameWork(packageName) + } } \ No newline at end of file diff --git a/app/src/main/java/com/github/droidworksstudio/launcher/ui/activities/MainActivity.kt b/app/src/main/java/com/github/droidworksstudio/launcher/ui/activities/MainActivity.kt index b45227d..bdecfcf 100644 --- a/app/src/main/java/com/github/droidworksstudio/launcher/ui/activities/MainActivity.kt +++ b/app/src/main/java/com/github/droidworksstudio/launcher/ui/activities/MainActivity.kt @@ -1,16 +1,14 @@ package com.github.droidworksstudio.launcher.ui.activities import android.annotation.SuppressLint -import android.app.admin.DevicePolicyManager -import android.content.Intent import android.content.pm.ActivityInfo import android.os.Build import android.os.Bundle import android.view.Menu import android.view.MenuItem import android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS -import android.widget.Toast import androidx.activity.viewModels +import androidx.annotation.RequiresApi import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.lifecycleScope import androidx.navigation.NavController @@ -19,7 +17,6 @@ import androidx.navigation.fragment.NavHostFragment import androidx.navigation.ui.AppBarConfiguration import androidx.navigation.ui.navigateUp import com.github.droidworksstudio.ktx.isTablet -import com.github.droidworksstudio.launcher.Constants import com.github.droidworksstudio.launcher.R import com.github.droidworksstudio.launcher.databinding.ActivityMainBinding import com.github.droidworksstudio.launcher.helper.AppHelper @@ -68,6 +65,7 @@ class MainActivity : AppCompatActivity() { } + @RequiresApi(Build.VERSION_CODES.R) private fun setupDataBase() { lifecycleScope.launch { viewModel.initializeInstalledAppInfo(this@MainActivity) @@ -118,6 +116,7 @@ class MainActivity : AppCompatActivity() { || super.onSupportNavigateUp() } + @RequiresApi(Build.VERSION_CODES.R) override fun onResume() { super.onResume() backToHomeScreen() diff --git a/app/src/main/java/com/github/droidworksstudio/launcher/ui/drawer/DrawAdapter.kt b/app/src/main/java/com/github/droidworksstudio/launcher/ui/drawer/DrawAdapter.kt index 5ab4f78..f72bfd0 100644 --- a/app/src/main/java/com/github/droidworksstudio/launcher/ui/drawer/DrawAdapter.kt +++ b/app/src/main/java/com/github/droidworksstudio/launcher/ui/drawer/DrawAdapter.kt @@ -37,7 +37,6 @@ class DrawAdapter( } override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { - val appInfo = getItem(position) (holder as DrawViewHolder).bind(appInfo) } diff --git a/app/src/main/java/com/github/droidworksstudio/launcher/ui/drawer/DrawFragment.kt b/app/src/main/java/com/github/droidworksstudio/launcher/ui/drawer/DrawFragment.kt index d3d96b1..0d5d080 100644 --- a/app/src/main/java/com/github/droidworksstudio/launcher/ui/drawer/DrawFragment.kt +++ b/app/src/main/java/com/github/droidworksstudio/launcher/ui/drawer/DrawFragment.kt @@ -2,6 +2,7 @@ package com.github.droidworksstudio.launcher.ui.drawer import android.annotation.SuppressLint import android.content.Context +import android.os.Build import android.os.Bundle import android.text.Spannable import android.text.SpannableString @@ -10,6 +11,7 @@ import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.annotation.RequiresApi import androidx.appcompat.widget.SearchView import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels @@ -64,7 +66,13 @@ class DrawFragment : Fragment(), private val viewModel: AppViewModel by viewModels() - private val drawAdapter: DrawAdapter by lazy { DrawAdapter(this, this, preferenceHelper) } + private val drawAdapter: DrawAdapter by lazy { + DrawAdapter( + this, + this, + preferenceHelper + ) + } private lateinit var context: Context override fun onCreateView( @@ -98,6 +106,7 @@ class DrawFragment : Fragment(), } } + @RequiresApi(Build.VERSION_CODES.R) private fun observeDrawerApps() { viewModel.compareInstalledAppInfo() @@ -242,12 +251,14 @@ class DrawFragment : Fragment(), binding.searchViewText.hideKeyboard() } + @RequiresApi(Build.VERSION_CODES.R) override fun onResume() { super.onResume() observeDrawerApps() if (preferenceHelper.automaticKeyboard) binding.searchViewText.showKeyboard() } + @RequiresApi(Build.VERSION_CODES.R) override fun onStart() { super.onStart() observeDrawerApps() diff --git a/app/src/main/java/com/github/droidworksstudio/launcher/ui/drawer/DrawViewHolder.kt b/app/src/main/java/com/github/droidworksstudio/launcher/ui/drawer/DrawViewHolder.kt index 010f495..1b0e03f 100644 --- a/app/src/main/java/com/github/droidworksstudio/launcher/ui/drawer/DrawViewHolder.kt +++ b/app/src/main/java/com/github/droidworksstudio/launcher/ui/drawer/DrawViewHolder.kt @@ -1,8 +1,14 @@ package com.github.droidworksstudio.launcher.ui.drawer import android.util.Log +import android.view.Gravity +import android.view.View +import androidx.appcompat.content.res.AppCompatResources import androidx.appcompat.widget.LinearLayoutCompat import androidx.recyclerview.widget.RecyclerView +import com.github.droidworksstudio.ktx.dpToPx +import com.github.droidworksstudio.ktx.isWorkProfileEnabled +import com.github.droidworksstudio.launcher.R import com.github.droidworksstudio.launcher.data.entities.AppInfo import com.github.droidworksstudio.launcher.databinding.ItemDrawBinding import com.github.droidworksstudio.launcher.helper.PreferenceHelper @@ -14,7 +20,9 @@ class DrawViewHolder( private val onAppLongClickedListener: OnItemClickedListener.OnAppLongClickedListener, private val preferenceHelper: PreferenceHelper ) : + RecyclerView.ViewHolder(binding.root) { + fun bind(appInfo: AppInfo) { binding.apply { val layoutParams = LinearLayoutCompat.LayoutParams( @@ -30,7 +38,28 @@ class DrawViewHolder( appDrawName.text = appInfo.appName appDrawName.setTextColor(preferenceHelper.appColor) appDrawName.textSize = preferenceHelper.appTextSize - Log.d("Tag", "Draw Adapter: ${appInfo.appName + appInfo.id}") + Log.d("Tag", "Draw Adapter: ${appInfo.appName + appInfo.id} | ${appInfo.work}") + val icon = AppCompatResources.getDrawable(appDrawName.context, R.drawable.work_profile) + val px = preferenceHelper.appTextSize.toInt().dpToPx() + icon?.setBounds(0, 0, px, px) + if (appInfo.work) { + val appLabelGravity = preferenceHelper.homeAppAlignment + + if (appLabelGravity == Gravity.START) { + appDrawName.setCompoundDrawables(icon, null, null, null) + } else { + appDrawName.setCompoundDrawables(null, null, icon, null) + } + appDrawName.compoundDrawablePadding = 20 + if (!appDrawName.context.isWorkProfileEnabled()) { + appDrawName.visibility = View.GONE + } + } else { + + // If appInfo.work is false, remove the drawable + appDrawName.setCompoundDrawables(null, null, null, null) + appDrawName.compoundDrawablePadding = 0 + } } itemView.setOnClickListener { diff --git a/app/src/main/java/com/github/droidworksstudio/launcher/viewmodel/AppViewModel.kt b/app/src/main/java/com/github/droidworksstudio/launcher/viewmodel/AppViewModel.kt index 73dadf6..66c9b6c 100644 --- a/app/src/main/java/com/github/droidworksstudio/launcher/viewmodel/AppViewModel.kt +++ b/app/src/main/java/com/github/droidworksstudio/launcher/viewmodel/AppViewModel.kt @@ -1,7 +1,9 @@ package com.github.droidworksstudio.launcher.viewmodel import android.content.Context +import android.os.Build import android.util.Log +import androidx.annotation.RequiresApi import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.github.droidworksstudio.launcher.data.entities.AppInfo @@ -22,47 +24,58 @@ class AppViewModel @Inject constructor( val drawApps: Flow> = appInfoRepository.getDrawApps().conflate() val favoriteApps: Flow> = appInfoRepository.getFavoriteApps().conflate() val hiddenApps: Flow> = appInfoRepository.getHiddenApps().conflate() + + @RequiresApi(Build.VERSION_CODES.R) fun initializeInstalledAppInfo(context: Context) { viewModelScope.launch { appInfoRepository.initInstalledAppInfo(context) } } + fun updateAppInfoFavorite(appInfo: AppInfo) { viewModelScope.launch { appInfoRepository.updateFavoriteAppInfo(appInfo) Log.d("Tag", "ViewModel Home Order : ${appInfo.appOrder}") } } + fun updateAppInfoAppName(appInfo: AppInfo, newAppName: String) { viewModelScope.launch { appInfoRepository.updateAppName(appInfo, newAppName) Log.d("Tag", "ViewModel Home Name : ${appInfo.appName}") } } + fun updateAppHidden(appInfo: AppInfo, appHidden: Boolean) { viewModelScope.launch { appInfoRepository.updateAppHidden(appInfo, appHidden) } } + fun updateAppLock(appInfo: AppInfo, appLock: Boolean) { viewModelScope.launch { appInfoRepository.updateAppLock(appInfo, appLock) } } + + @RequiresApi(Build.VERSION_CODES.R) fun compareInstalledAppInfo() { viewModelScope.launch { appInfoRepository.compareInstalledApp() } } + suspend fun updateAppOrder(appInfoList: List) { withContext(Dispatchers.IO) { appInfoRepository.updateAppOrder(appInfoList) } } + fun update(appInfo: AppInfo) { viewModelScope.launch { appInfoRepository.updateInfo(appInfo) } } + fun searchAppInfo(query: String?) = appInfoRepository.searchNote(query) } diff --git a/app/src/main/res/drawable/work_profile.xml b/app/src/main/res/drawable/work_profile.xml new file mode 100644 index 0000000..c4637cc --- /dev/null +++ b/app/src/main/res/drawable/work_profile.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_draw.xml b/app/src/main/res/layout/fragment_draw.xml index 1dd6e70..1d68b42 100644 --- a/app/src/main/res/layout/fragment_draw.xml +++ b/app/src/main/res/layout/fragment_draw.xml @@ -53,7 +53,7 @@