commit 57721ac89bd820d1e4c63223731852abbf2351a6 Author: ottoptj Date: Mon May 6 18:58:06 2024 +0300 Launcher so far, app menu partially working diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..e312f9b --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,52 @@ +plugins { + id("com.android.application") + id("org.jetbrains.kotlin.android") +} + +android { + namespace = "eu.ottop.yamlauncher" + compileSdk = 34 + + defaultConfig { + applicationId = "eu.ottop.yamlauncher" + minSdk = 31 + targetSdk = 34 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = "1.8" + } + buildFeatures { + viewBinding = true + } +} + +dependencies { + + implementation("androidx.core:core-ktx:1.12.0") + implementation("androidx.appcompat:appcompat:1.6.1") + implementation("com.google.android.material:material:1.11.0") + implementation("androidx.constraintlayout:constraintlayout:2.1.4") + implementation("androidx.navigation:navigation-fragment-ktx:2.6.0") + implementation("androidx.navigation:navigation-ui-ktx:2.6.0") + testImplementation("junit:junit:4.13.2") + androidTestImplementation("androidx.test.ext:junit:1.1.5") + androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/src/androidTest/java/eu/ottop/yamlauncher/ExampleInstrumentedTest.kt b/app/src/androidTest/java/eu/ottop/yamlauncher/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..fbc5179 --- /dev/null +++ b/app/src/androidTest/java/eu/ottop/yamlauncher/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package eu.ottop.yamlauncher + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("eu.ottop.yamlauncher", appContext.packageName) + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..84bb871 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/eu/ottop/yamlauncher/AppMenuActivity.kt b/app/src/main/java/eu/ottop/yamlauncher/AppMenuActivity.kt new file mode 100644 index 0000000..6671b6a --- /dev/null +++ b/app/src/main/java/eu/ottop/yamlauncher/AppMenuActivity.kt @@ -0,0 +1,220 @@ +package eu.ottop.yamlauncher + +import android.content.Context +import android.content.pm.LauncherActivityInfo +import android.content.pm.LauncherApps +import android.content.res.ColorStateList +import android.graphics.Color +import android.graphics.drawable.Drawable +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import android.os.UserHandle +import android.util.Log +import android.view.Gravity +import android.view.View +import android.widget.LinearLayout +import android.widget.SearchView +import android.widget.TextView +import android.widget.Toast +import androidx.core.content.ContextCompat +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentActivity +import androidx.viewpager2.adapter.FragmentStateAdapter +import androidx.viewpager2.widget.ViewPager2 +import com.google.android.material.tabs.TabLayout +import com.google.android.material.tabs.TabLayoutMediator +import eu.ottop.yamlauncher.databinding.ActivityAppMenuBinding +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import java.util.SortedMap + +class AppMenuActivity : AppCompatActivity() { + + private lateinit var binding: ActivityAppMenuBinding + private lateinit var searchView: SearchView + private lateinit var container: LinearLayout + private lateinit var shownApps: List>> + private var checkApps: Job? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivityAppMenuBinding.inflate(layoutInflater) + setContentView(binding.root) + setSupportActionBar(null) + shownApps = listOf>>() + searchView = findViewById(R.id.searchView) + container = findViewById(R.id.container) + + // Set a listener on the search view + searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { + override fun onQueryTextSubmit(query: String?): Boolean { + searchView.clearFocus() + return true + } + + override fun onQueryTextChange(newText: String?): Boolean { + // Filter items based on the search query + filterItems(newText) + return true + } + + }) + + binding.root.addOnLayoutChangeListener { view, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom -> + if (bottom - top > oldBottom - oldTop) { + searchView.clearFocus() + } + } + + } + + override fun onStop() { + super.onStop() + checkApps?.cancel() + } + + override fun onStart() { + super.onStart() + startTask() + } + + private fun startTask() { + checkApps = GlobalScope.launch { + while (true) { + if (!listsEqual(shownApps, getInstalledPersonalApps())) { + Log.d("AHAHHAHAA","AHJAHAHA") + shownApps = getInstalledPersonalApps() + runOnUiThread { + deleteAppMenuContents() + createPersonalAppMenu() + } + + } + delay(1000) + } + } + } + + private fun listsEqual(list1: List>>, list2: List>>): Boolean { + if (list1.size != list2.size) return false + + for (i in list1.indices) { + if (list1[i].first.componentName != list2[i].first.componentName || list1[i].second.first != list2[i].second.first) { + return false + } + } + + return true + } + + private fun filterItems(query: String?) { + val cleanQuery = query?.replace("[^a-zA-Z0-9]".toRegex(), "") + + for (i in 0 until container.childCount) { + val view = container.getChildAt(i) + + if (view is TextView) { + val itemText = view.text.toString() + val cleanItemText = itemText.replace("[^a-zA-Z0-9]".toRegex(), "") + + if (cleanItemText.contains(cleanQuery ?: "", ignoreCase = true)) { + view.visibility = View.VISIBLE + } else { + view.visibility = View.GONE + } + } + } + } + + private fun getInstalledApps(): List>> { + val allApps = mutableListOf>>() + val launcherApps = this.getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps + for (i in launcherApps.profiles.indices) { + launcherApps.getActivityList(null, launcherApps.profiles[i]).forEach { app -> + allApps.add(Pair(app, Pair(launcherApps.profiles[i], i))) + } + + } + return allApps.sortedBy { it.first.label.toString().lowercase() } + } + + private fun getInstalledPersonalApps(): List>> { + return getInstalledApps() + } + + private fun getInstalledWorkApps(): List>> { + return getInstalledApps() + } + + private fun createAppMenu(appInfo: LauncherActivityInfo, userHandle: UserHandle, workProfile: Int): Boolean { + val appInfo = appInfo.activityInfo.applicationInfo + val textView = TextView(this) + + val states = arrayOf( + intArrayOf(-android.R.attr.state_pressed), + intArrayOf(android.R.attr.state_pressed) + ) + + val colors = intArrayOf( + Color.parseColor("#f3f3f3"), // Default text color + Color.parseColor("#c3c3c3") // Text color when pressed + ) + + with(textView) { + textSize = 28f + setPadding(0,0,0,50) + isClickable = true + focusable = View.FOCUSABLE + gravity = Gravity.START + + if (workProfile != 0) { + text = "*"+appInfo.loadLabel(packageManager) + } + else { + text = appInfo.loadLabel(packageManager) + } + setTextColor(ColorStateList(states, colors)) + } + + + textView.setOnLongClickListener { + Toast.makeText(this, "Long press detected on ${appInfo.loadLabel(packageManager)}", Toast.LENGTH_SHORT).show() + + true + } + + textView.setOnClickListener { + val launcherApps = getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps + val packageName = appInfo.packageName + + val mainActivity = launcherApps.getActivityList(packageName, userHandle).firstOrNull() + + if (mainActivity != null) { + launcherApps.startMainActivity(mainActivity.componentName, userHandle, null, null) + } else { + Toast.makeText(this, "Unable to launch ${appInfo.loadLabel(packageManager)}", Toast.LENGTH_SHORT).show() + } + + } + + // Add the button to the LinearLayout + binding.container.addView(textView) + + return true + } + + private fun createPersonalAppMenu(): Boolean { + val pApps = getInstalledPersonalApps() + pApps.forEach { appInfo -> + createAppMenu(appInfo.first, appInfo.second.first, appInfo.second.second) + } + return true + } + + private fun deleteAppMenuContents(): Boolean { + binding.container.removeAllViewsInLayout() + return true + } +} diff --git a/app/src/main/java/eu/ottop/yamlauncher/MainActivity.kt b/app/src/main/java/eu/ottop/yamlauncher/MainActivity.kt new file mode 100644 index 0000000..fa72616 --- /dev/null +++ b/app/src/main/java/eu/ottop/yamlauncher/MainActivity.kt @@ -0,0 +1,40 @@ +package eu.ottop.yamlauncher + +import android.content.Intent +import android.content.res.ColorStateList +import android.graphics.Color +import android.os.Bundle +import android.view.Gravity +import android.view.Menu +import android.view.MenuItem +import android.view.MotionEvent +import android.view.View +import android.view.View.FOCUSABLE +import android.view.View.OnFocusChangeListener +import android.widget.LinearLayout +import android.widget.SearchView +import android.widget.TextView +import android.widget.Toast +import androidx.appcompat.app.AppCompatActivity +import androidx.navigation.findNavController +import androidx.navigation.ui.AppBarConfiguration +import androidx.navigation.ui.navigateUp +import eu.ottop.yamlauncher.databinding.ActivityMainBinding + +class MainActivity : AppCompatActivity() { + + private lateinit var binding: ActivityMainBinding + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivityMainBinding.inflate(layoutInflater) + setContentView(binding.root) + setSupportActionBar(null) + + } + + fun openAppMenuActivity(view: View) { + startActivity(Intent(this, AppMenuActivity::class.java)) + } + +} \ No newline at end of file diff --git a/app/src/main/java/eu/ottop/yamlauncher/PersonalAppsFragment.kt b/app/src/main/java/eu/ottop/yamlauncher/PersonalAppsFragment.kt new file mode 100644 index 0000000..4e70ec3 --- /dev/null +++ b/app/src/main/java/eu/ottop/yamlauncher/PersonalAppsFragment.kt @@ -0,0 +1,241 @@ +package eu.ottop.yamlauncher + +import android.content.Context +import android.content.pm.LauncherActivityInfo +import android.content.pm.LauncherApps +import android.content.res.ColorStateList +import android.graphics.Color +import android.os.Bundle +import android.os.UserHandle +import android.util.Log +import android.view.Gravity +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.LinearLayout +import android.widget.SearchView +import android.widget.TextView +import android.widget.Toast +import androidx.core.content.getSystemService +import com.google.android.material.tabs.TabLayout +import com.google.android.material.tabs.TabLayoutMediator +import eu.ottop.yamlauncher.databinding.ActivityAppMenuBinding +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch + +// TODO: Rename parameter arguments, choose names that match +// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER +private const val ARG_PARAM1 = "param1" +private const val ARG_PARAM2 = "param2" + +/** + * A simple [Fragment] subclass. + * Use the [PersonalAppsFragment.newInstance] factory method to + * create an instance of this fragment. + */ +class PersonalAppsFragment : Fragment() { + + private lateinit var binding: ActivityAppMenuBinding + private lateinit var searchView: SearchView + private lateinit var container: LinearLayout + private lateinit var tabLayout: TabLayout + private var checkApps: Job? = null + private lateinit var shownApps: List + + + override fun onCreateView( + inflater: LayoutInflater, viewContainer: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val view = inflater.inflate(R.layout.fragment_personal_apps, viewContainer, false) + + // Initialize views from the fragment layout + container = view.findViewById(R.id.container) + searchView = requireActivity().findViewById(R.id.searchView) + + shownApps = listOf() + + searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { + override fun onQueryTextSubmit(query: String?): Boolean { + searchView.clearFocus() + return true + } + + override fun onQueryTextChange(newText: String?): Boolean { + // Filter items based on the search query + filterItems(newText) + return true + } + + }) + + return view + } + + override fun onPause() { + super.onPause() + checkApps?.cancel() + searchView.setOnQueryTextListener(null) + } + + override fun onStart() { + super.onStart() + startTask() + } + + private fun filterItems(query: String?) { + val cleanQuery = query?.replace("[^a-zA-Z0-9]".toRegex(), "") + + for (i in 0 until container.childCount) { + val view = container.getChildAt(i) + + if (view is TextView) { + val itemText = view.text.toString() + val cleanItemText = itemText.replace("[^a-zA-Z0-9]".toRegex(), "") + + if (cleanItemText.contains(cleanQuery ?: "", ignoreCase = true)) { + view.visibility = View.VISIBLE + } else { + view.visibility = View.GONE + } + } + } + } + + private fun startTask() { + checkApps = GlobalScope.launch { + while (true) { + Log.d("APPSITUATION", "Ahahahaha") + if (!listsEqual(shownApps, getInstalledPersonalApps())) { + shownApps = getInstalledPersonalApps() + requireActivity().runOnUiThread { + deleteAppMenuContents() + createPersonalAppMenu() + } + + } + delay(1000) + } + } + } + + private fun listsEqual( + list1: List, + list2: List + ): Boolean { + if (list1.size != list2.size) return false + + for (i in list1.indices) { + if (list1[i].label != list2[i].label) { + return false + } + } + + return true + } + + private fun getInstalledApps(profile: Int): List { + val allApps = mutableListOf() + val launcherApps = + requireActivity().getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps + + allApps.addAll(launcherApps.getActivityList(null, launcherApps.profiles[profile])) + + return allApps.sortedWith(compareBy { + it.applicationInfo.loadLabel(requireActivity().packageManager).toString().lowercase() + }) + } + + private fun getInstalledPersonalApps(): List { + return getInstalledApps(0) + } + + private fun createAppMenu( + appInfo: LauncherActivityInfo, + userHandle: UserHandle, + workProfile: Boolean + ): Boolean { + val appInfo = appInfo.activityInfo.applicationInfo + val textView = TextView(requireContext()) + textView.textSize = 28f + textView.setPadding(0, 0, 0, 50) + + val states = arrayOf( + intArrayOf(-android.R.attr.state_pressed), + intArrayOf(android.R.attr.state_pressed) + ) + + val colors = intArrayOf( + Color.parseColor("#f3f3f3"), // Default text color + Color.parseColor("#c3c3c3") // Text color when pressed + ) + + textView.setTextColor(ColorStateList(states, colors)) + + textView.isClickable = true + textView.focusable = View.FOCUSABLE + textView.gravity = Gravity.START + textView.text = appInfo.loadLabel(requireActivity().packageManager) + + textView.setOnLongClickListener { + Toast.makeText( + requireContext(), + "Long press detected on ${appInfo.loadLabel(requireActivity().packageManager)}", + Toast.LENGTH_SHORT + ).show() + + true + } + + textView.setOnClickListener { + val launcherApps = + requireActivity().getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps + val packageName = appInfo.packageName + + val mainActivity = launcherApps.getActivityList(packageName, userHandle).firstOrNull() + + if (mainActivity != null) { + launcherApps.startMainActivity(mainActivity.componentName, userHandle, null, null) + } else { + Toast.makeText( + requireContext(), + "Unable to launch ${appInfo.loadLabel(requireActivity().packageManager)}", + Toast.LENGTH_SHORT + ).show() + } + + } + + // Add the button to the LinearLayout + container.addView(textView) + + return true + } + + private fun createPersonalAppMenu(): Boolean { + val pApps = getInstalledPersonalApps() + pApps.forEach { appInfo -> + createAppMenu(appInfo, pApps.first().user, false) + } + return true + } + + private fun deleteAppMenuContents(): Boolean { + binding.container.removeAllViewsInLayout() + return true + + } + + fun setActivityReferences(binding: ActivityAppMenuBinding) { + this.binding = binding + } + + companion object { + fun newInstance(binding: ActivityAppMenuBinding) = PersonalAppsFragment().apply { + this.binding = binding + } + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/ottop/yamlauncher/WorkAppsFragment.kt b/app/src/main/java/eu/ottop/yamlauncher/WorkAppsFragment.kt new file mode 100644 index 0000000..1cefc46 --- /dev/null +++ b/app/src/main/java/eu/ottop/yamlauncher/WorkAppsFragment.kt @@ -0,0 +1,237 @@ +package eu.ottop.yamlauncher + +import android.content.Context +import android.content.pm.LauncherActivityInfo +import android.content.pm.LauncherApps +import android.content.res.ColorStateList +import android.graphics.Color +import android.os.Bundle +import android.os.UserHandle +import android.util.Log +import android.view.Gravity +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.LinearLayout +import android.widget.SearchView +import android.widget.TextView +import android.widget.Toast +import com.google.android.material.tabs.TabLayout +import eu.ottop.yamlauncher.databinding.ActivityAppMenuBinding +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch + +// TODO: Rename parameter arguments, choose names that match +// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER +private const val ARG_PARAM1 = "param1" +private const val ARG_PARAM2 = "param2" + +/** + * A simple [Fragment] subclass. + * Use the [WorkAppsFragment.newInstance] factory method to + * create an instance of this fragment. + */ +class WorkAppsFragment : Fragment() { + private lateinit var binding: ActivityAppMenuBinding + private lateinit var searchView: SearchView + private lateinit var container: LinearLayout + private lateinit var tabLayout: TabLayout + private var checkApps: Job? = null + private lateinit var shownApps: List + + + override fun onCreateView( + inflater: LayoutInflater, viewContainer: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val view = inflater.inflate(R.layout.fragment_personal_apps, viewContainer, false) + + // Initialize views from the fragment layout + container = view.findViewById(R.id.container) + searchView = requireActivity().findViewById(R.id.searchView) + + shownApps = listOf() + + searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { + override fun onQueryTextSubmit(query: String?): Boolean { + searchView.clearFocus() + return true + } + + override fun onQueryTextChange(newText: String?): Boolean { + + filterItems(newText) + return true + } + + }) + + return view + } + + override fun onPause() { + super.onPause() + checkApps?.cancel() + } + + override fun onStart() { + super.onStart() + startTask() + } + + private fun filterItems(query: String?) { + val cleanQuery = query?.replace("[^a-zA-Z0-9]".toRegex(), "") + + for (i in 0 until container.childCount) { + val view = container.getChildAt(i) + + if (view is TextView) { + val itemText = view.text.toString() + val cleanItemText = itemText.replace("[^a-zA-Z0-9]".toRegex(), "") + + if (cleanItemText.contains(cleanQuery ?: "", ignoreCase = true)) { + view.visibility = View.VISIBLE + } else { + view.visibility = View.GONE + } + } + } + } + + private fun startTask() { + checkApps = GlobalScope.launch { + while (true) { + Log.d("APPSITUATION1234", "Ahahahaha") + if (!listsEqual(shownApps, getInstalledWorkApps())) { + shownApps = getInstalledWorkApps() + requireActivity().runOnUiThread { + deleteAppMenuContents() + createWorkAppMenu() + } + + } + delay(1000) + } + } + } + + private fun listsEqual( + list1: List, + list2: List + ): Boolean { + if (list1.size != list2.size) return false + + for (i in list1.indices) { + if (list1[i].label != list2[i].label) { + return false + } + } + + return true + } + + private fun getInstalledApps(profile: Int): List { + val allApps = mutableListOf() + val launcherApps = + requireActivity().getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps + + allApps.addAll(launcherApps.getActivityList(null, launcherApps.profiles[profile])) + + return allApps.sortedWith(compareBy { + it.applicationInfo.loadLabel(requireActivity().packageManager).toString().lowercase() + }) + } + + private fun getInstalledWorkApps(): List { + return getInstalledApps(1) + } + + private fun createAppMenu( + appInfo: LauncherActivityInfo, + userHandle: UserHandle, + workProfile: Boolean + ): Boolean { + val appInfo = appInfo.activityInfo.applicationInfo + val textView = TextView(requireContext()) + textView.textSize = 28f + textView.setPadding(0, 0, 0, 50) + + val states = arrayOf( + intArrayOf(-android.R.attr.state_pressed), + intArrayOf(android.R.attr.state_pressed) + ) + + val colors = intArrayOf( + Color.parseColor("#f3f3f3"), // Default text color + Color.parseColor("#c3c3c3") // Text color when pressed + ) + + textView.setTextColor(ColorStateList(states, colors)) + + textView.isClickable = true + textView.focusable = View.FOCUSABLE + textView.gravity = Gravity.START + textView.text = appInfo.loadLabel(requireActivity().packageManager) + + textView.setOnLongClickListener { + Toast.makeText( + requireContext(), + "Long press detected on ${appInfo.loadLabel(requireActivity().packageManager)}", + Toast.LENGTH_SHORT + ).show() + + true + } + + textView.setOnClickListener { + val launcherApps = + requireActivity().getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps + val packageName = appInfo.packageName + + val mainActivity = launcherApps.getActivityList(packageName, userHandle).firstOrNull() + + if (mainActivity != null) { + launcherApps.startMainActivity(mainActivity.componentName, userHandle, null, null) + } else { + Toast.makeText( + requireContext(), + "Unable to launch ${appInfo.loadLabel(requireActivity().packageManager)}", + Toast.LENGTH_SHORT + ).show() + } + + } + + // Add the button to the LinearLayout + container.addView(textView) + + return true + } + + private fun createWorkAppMenu(): Boolean { + val pApps = getInstalledWorkApps() + pApps.forEach { appInfo -> + createAppMenu(appInfo, pApps.first().user, false) + } + return true + } + + private fun deleteAppMenuContents(): Boolean { + binding.container.removeAllViewsInLayout() + return true + + } + + fun setActivityReferences(binding: ActivityAppMenuBinding) { + this.binding = binding + } + + companion object { + fun newInstance(binding: ActivityAppMenuBinding) = WorkAppsFragment().apply { + this.binding = binding + } + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_app_menu.xml b/app/src/main/res/layout/activity_app_menu.xml new file mode 100644 index 0000000..966643c --- /dev/null +++ b/app/src/main/res/layout/activity_app_menu.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..cd6422a --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,22 @@ + + + +