diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7d98f90..1d5250d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -23,10 +23,10 @@ - - - - + + diff --git a/app/src/main/java/com/finnmglas/launcher/ChooseActivity.kt b/app/src/main/java/com/finnmglas/launcher/ChooseActivity.kt index 6215afb..ee64b1e 100644 --- a/app/src/main/java/com/finnmglas/launcher/ChooseActivity.kt +++ b/app/src/main/java/com/finnmglas/launcher/ChooseActivity.kt @@ -2,9 +2,9 @@ package com.finnmglas.launcher import android.annotation.SuppressLint import android.content.Intent -import android.content.pm.ApplicationInfo import android.graphics.Color import android.os.Bundle +import android.view.View import android.view.WindowManager import android.widget.TextView import androidx.appcompat.app.AppCompatActivity @@ -13,44 +13,8 @@ import kotlinx.android.synthetic.main.activity_choose.* class ChooseActivity : AppCompatActivity() { - private fun listApps() { - val mainIntent = Intent(Intent.ACTION_MAIN, null) - mainIntent.addCategory(Intent.CATEGORY_LAUNCHER) - - val pm = packageManager - val apps = pm.getInstalledApplications(0) - - val installedApps: MutableList = ArrayList() - - // list - for (app in apps) { - - if (app.flags and ApplicationInfo.FLAG_UPDATED_SYSTEM_APP != 0) { - //checks for flags; if flagged, check if updated system app - installedApps.add(app) - } else if (app.flags and ApplicationInfo.FLAG_SYSTEM != 0) { - //it's a system app, not interested - } else { - //in this case, it should be a user-installed app - installedApps.add(app) - } - } - - // ui - for (app in installedApps) { - //packageInfo.sourceDir - pm.getLaunchIntentForPackage(app.packageName) - - // creating TextView programmatically - val tvdynamic = TextView(this) - tvdynamic.textSize = 20f - tvdynamic.text = app.loadLabel(pm).toString() - tvdynamic.setTextColor(Color.parseColor("#cccccc")) - - tvdynamic.setOnClickListener { startActivity(pm.getLaunchIntentForPackage(app.packageName)) } - - apps_list.addView(tvdynamic) - } + fun backHome(view: View) { + finish() } @SuppressLint("SetTextI18n") // I do not care @@ -61,6 +25,51 @@ class ChooseActivity : AppCompatActivity() { window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) setContentView(R.layout.activity_choose) - listApps() + + val bundle = intent.extras + val action = bundle!!.getString("action") // why choose an app + val forApp = bundle.getString("forApp") // which app we choose + + /* Build Layout */ + + // TODO: Make this more efficient, faster, generate the list before + + val mainIntent = Intent(Intent.ACTION_MAIN, null) + mainIntent.addCategory(Intent.CATEGORY_LAUNCHER) + + val pm = packageManager + val i = Intent(Intent.ACTION_MAIN) + i.addCategory(Intent.CATEGORY_LAUNCHER) + val apps = pm.queryIntentActivities(i, 0) + + apps.sortBy { it.activityInfo.loadLabel(pm).toString() } + + for (resolveInfo in apps) { + val app = resolveInfo.activityInfo + pm.getLaunchIntentForPackage(app.packageName) + + // creating TextView programmatically + val tvdynamic = TextView(this) + tvdynamic.textSize = 24f + tvdynamic.text = app.loadLabel(pm).toString() + tvdynamic.setTextColor(Color.parseColor("#cccccc")) + + if (action == "run"){ + tvdynamic.setOnClickListener { startActivity(pm.getLaunchIntentForPackage(app.packageName)) } + } + else if (action == "pick"){ + tvdynamic.setOnClickListener { + val returnIntent = Intent() + returnIntent.putExtra("value", app.packageName) + returnIntent.putExtra("forApp", forApp) + setResult( + 5000, + returnIntent + ) + finish() + } + } + apps_list.addView(tvdynamic) + } } } diff --git a/app/src/main/java/com/finnmglas/launcher/MainActivity.kt b/app/src/main/java/com/finnmglas/launcher/MainActivity.kt index 69eb915..ecf0fd3 100644 --- a/app/src/main/java/com/finnmglas/launcher/MainActivity.kt +++ b/app/src/main/java/com/finnmglas/launcher/MainActivity.kt @@ -1,135 +1,105 @@ package com.finnmglas.launcher import android.annotation.SuppressLint +import android.content.Context import android.content.Intent -import android.content.pm.PackageManager -import android.content.pm.ResolveInfo +import android.content.SharedPreferences +import android.content.SharedPreferences.Editor import android.os.Bundle import android.util.DisplayMetrics -import android.view.KeyEvent -import android.view.MotionEvent -import android.view.View -import android.view.WindowManager -import android.widget.TextView +import android.view.* import android.widget.Toast import androidx.appcompat.app.AppCompatActivity -import androidx.core.view.MotionEventCompat +import androidx.core.view.GestureDetectorCompat import kotlinx.android.synthetic.main.activity_main.* -import kotlin.math.abs import java.text.SimpleDateFormat import java.util.* import kotlin.concurrent.fixedRateTimer +import kotlin.math.abs + +// App Launch Actions +var upApp = "" +var downApp = "" +var rightApp = "" +var leftApp = "" +var volumeUpApp = "" +var volumeDownApp = "" + +class MainActivity : AppCompatActivity(), +GestureDetector.OnGestureListener, +GestureDetector.OnDoubleTapListener { -class MainActivity : AppCompatActivity() { + private lateinit var mDetector: GestureDetectorCompat + // get device dimensions val displayMetrics = DisplayMetrics() - private fun getIntent(packageName: String) : Intent? { + private fun getIntent(packageName: String): Intent? { val pm = applicationContext.packageManager - val intent:Intent? = pm.getLaunchIntentForPackage(packageName) + val intent: Intent? = pm.getLaunchIntentForPackage(packageName) intent?.addCategory(Intent.CATEGORY_LAUNCHER) - return intent; + return intent } private fun launchApp(packageName: String, fallback: String = "") { val intent1 = getIntent(packageName) - if(intent1!=null){ + if (intent1 != null) { applicationContext.startActivity(intent1) - overridePendingTransition(0,0) + overridePendingTransition(0, 0) } else { val intent2 = getIntent(fallback) - if(intent2!=null){ + if (intent2 != null) { applicationContext.startActivity(intent2) - overridePendingTransition(0,0) + overridePendingTransition(0, 0) } else { - Toast.makeText(this, "Package '$packageName' not found.", Toast.LENGTH_SHORT).show() + Toast.makeText( + this, + "Package '$packageName' not found. Change your Settings.", + Toast.LENGTH_SHORT + ).show() } } } - fun launchInstagram(v: View){ launchApp("com.instagram.android") } - fun launchWhatsapp(v: View){ launchApp("com.whatsapp") } + fun launchCalendar(v: View) { + launchApp("com.google.android.calendar", "com.samsung.android.calendar") + } - fun launchFinder(v: View){ launchApp("com.samsung.android.app.galaxyfinder") } - fun launchMail(v: View){ launchApp("com.samsung.android.email.provider", "com.google.android.gm") } - fun launchCalendar(v: View){ launchApp("com.google.android.calendar", "com.samsung.android.calendar") } - fun launchClock(v: View){ launchApp("com.sec.android.app.clockpackage") } - fun launchBrowser(v: View){ launchApp("org.mozilla.firefox", "com.sec.android.app.sbrowser") } + fun launchClock(v: View) { + launchApp("com.sec.android.app.clockpackage") + } - fun launchUpApp() { launchBrowser(container) } - fun launchDownApp() { launchFinder(container) } - fun lauchLeftApp() { launchCalendar(container) } - fun lauchRightApp() { launchMail(container) } + fun launchUpApp() { + launchApp(upApp) + } + + fun launchDownApp() { + launchApp(downApp) + } + + fun lauchLeftApp() { + launchApp(leftApp) + } + + fun lauchRightApp() { + launchApp(rightApp) + } + + fun lauchVolumeUpApp() { + launchApp(volumeUpApp) + } - fun lauchVolumeUpApp() { } fun lauchVolumeDownApp() { - val intent = Intent(this, ChooseActivity::class.java) - startActivity(intent) + launchApp(volumeDownApp) } - // Overrides - - var touchX : Float = 0F - var touchY : Float = 0F - - override fun onTouchEvent(event: MotionEvent): Boolean { - - return when (MotionEventCompat.getActionMasked(event)) { - MotionEvent.ACTION_DOWN -> { - touchX = event.x - touchY = event.y - true - } - MotionEvent.ACTION_MOVE -> { - true - } - MotionEvent.ACTION_UP -> { - windowManager.defaultDisplay.getMetrics(displayMetrics) - - val width = displayMetrics.widthPixels - val height = displayMetrics.heightPixels - - val diffX = touchX - event.x - val diffY = touchY - event.y - - val strictness = 4 // of direction - - // Decide which one to open - - if (diffY > height/8 - && abs(diffY) > strictness * abs(diffX)) - launchUpApp() - - else if (diffY < -height/8 - && abs(diffY) > strictness * abs(diffX) - && touchY > 100) - launchDownApp() - - else if (diffX > width/4 - && abs(diffX) > strictness * abs(diffY)) - lauchLeftApp() - - else if (diffX < -width/4 - && abs(diffX) > strictness * abs(diffY)) - lauchRightApp() - - true - } - MotionEvent.ACTION_CANCEL -> { - true - } - MotionEvent.ACTION_OUTSIDE -> { - true - } - else -> super.onTouchEvent(event) - } - } + /* Overrides */ override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { - if (keyCode == KeyEvent.KEYCODE_BACK) { return true } + if (keyCode == KeyEvent.KEYCODE_BACK) return true else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) lauchVolumeUpApp() else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) lauchVolumeDownApp() return true @@ -139,15 +109,27 @@ class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN) + // Preferences + val sharedPref = this.getSharedPreferences( + getString(R.string.preference_file_key), Context.MODE_PRIVATE) + + // First Startup + if (!sharedPref.getBoolean("startedBefore", false)) + resetSettings(sharedPref) + + loadSettings(sharedPref) + + // Flags + + window.setFlags( + WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN + ) window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) val timeFormat = SimpleDateFormat("HH:mm:ss", Locale.getDefault()) - //dateFormat.timeZone = TimeZone.getTimeZone("GMT") - //timeFormat.timeZone = TimeZone.getTimeZone("GMT") - fixedRateTimer("timer", false, 0L, 1000) { this@MainActivity.runOnUiThread { dateView.text = dateFormat.format(Date()) @@ -157,5 +139,85 @@ class MainActivity : AppCompatActivity() { setContentView(R.layout.activity_main) + mDetector = GestureDetectorCompat(this, this) + mDetector.setOnDoubleTapListener(this) } + + override fun onTouchEvent(event: MotionEvent): Boolean { + return if (mDetector.onTouchEvent(event)) { + true + } else { + super.onTouchEvent(event) + } + } + + override fun onDown(event: MotionEvent): Boolean { + return true + } + + override fun onFling( + e1: MotionEvent, + e2: MotionEvent, + differenceX: Float, + differenceY: Float + ): Boolean { + + windowManager.defaultDisplay.getMetrics(displayMetrics) + val width = displayMetrics.widthPixels + val height = displayMetrics.heightPixels + + val diffX = e1.x - e2.x + val diffY = e1.y - e2.y + + val strictness = 4 // of direction + + /* Decide for an action */ + + if (diffY > height / 8 && abs(diffY) > strictness * abs(diffX)) launchUpApp() + // Only open if the swipe was not from the phone edge + else if (diffY < -height / 8 && abs(diffY) > strictness * abs(diffX) && e1.y > 100) launchDownApp() + else if (diffX > width / 4 && abs(diffX) > strictness * abs(diffY)) lauchLeftApp() + else if (diffX < -width / 4 && abs(diffX) > strictness * abs(diffY)) lauchRightApp() + + return true + } + + // Open Settings + override fun onLongPress(event: MotionEvent) { + startActivity(Intent(this, SettingsActivity::class.java)) + } + + override fun onScroll( + e1: MotionEvent, + e2: MotionEvent, + diffX: Float, + diffY: Float + ): Boolean { + return true + } + + override fun onShowPress(event: MotionEvent) { + + } + + override fun onSingleTapUp(event: MotionEvent): Boolean { + + return true + } + + override fun onDoubleTap(event: MotionEvent): Boolean { + + return true + } + + override fun onDoubleTapEvent(event: MotionEvent): Boolean { + + return true + } + + override fun onSingleTapConfirmed(event: MotionEvent): Boolean { + + return true + } + } diff --git a/app/src/main/java/com/finnmglas/launcher/Settings.kt b/app/src/main/java/com/finnmglas/launcher/Settings.kt new file mode 100644 index 0000000..82c9595 --- /dev/null +++ b/app/src/main/java/com/finnmglas/launcher/Settings.kt @@ -0,0 +1,27 @@ +package com.finnmglas.launcher + +import android.content.SharedPreferences + +fun resetSettings(sharedPref : SharedPreferences){ + val editor: SharedPreferences.Editor = sharedPref.edit() + + // Set Defaults + editor.putString("action_upApp", "org.mozilla.firefox") + editor.putString("action_downApp", "com.samsung.android.app.galaxyfinder") + editor.putString("action_rightApp", "com.samsung.android.email.provider") + editor.putString("action_leftApp", "com.google.android.calendar") + editor.putString("action_volumeUpApp", "com.whatsapp") + editor.putString("action_volumeDownApp", "com.sec.android.app.popupcalculator") + + editor.putBoolean("startedBefore", true) // never run this again + editor.apply() +} + +fun loadSettings(sharedPref : SharedPreferences){ + upApp = sharedPref.getString("action_upApp", "").toString() + downApp = sharedPref.getString("action_downApp", "").toString() + rightApp = sharedPref.getString("action_rightApp", "").toString() + leftApp = sharedPref.getString("action_leftApp", "").toString() + volumeUpApp = sharedPref.getString("action_volumeUpApp", "").toString() + volumeDownApp = sharedPref.getString("action_volumeDownApp", "").toString() +} \ No newline at end of file diff --git a/app/src/main/java/com/finnmglas/launcher/SettingsActivity.kt b/app/src/main/java/com/finnmglas/launcher/SettingsActivity.kt new file mode 100644 index 0000000..01ce2d2 --- /dev/null +++ b/app/src/main/java/com/finnmglas/launcher/SettingsActivity.kt @@ -0,0 +1,104 @@ +package com.finnmglas.launcher + +import android.annotation.SuppressLint +import android.app.AlertDialog +import android.content.Context +import android.content.DialogInterface +import android.content.Intent +import android.content.SharedPreferences +import android.net.Uri +import android.os.Bundle +import android.view.View +import android.view.WindowManager +import androidx.appcompat.app.AppCompatActivity + + +class SettingsActivity : AppCompatActivity() { + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + if(requestCode == 5000) + { + val value = data?.getStringExtra("value") + val forApp = data?.getStringExtra("forApp") ?: return + + // Save the new App to Preferences + val sharedPref = this.getSharedPreferences( + getString(R.string.preference_file_key), Context.MODE_PRIVATE) + + val editor :SharedPreferences.Editor = sharedPref.edit() + editor.putString("action_$forApp", value.toString()) + editor.apply() + + // Update running App + if (forApp == "downApp") downApp = value.toString() + else if (forApp == "upApp") upApp = value.toString() + else if (forApp == "leftApp") leftApp = value.toString() + else if (forApp == "rightApp") rightApp = value.toString() + else if (forApp == "volumeDownApp") volumeDownApp = value.toString() + else if (forApp == "volumeUpApp") volumeUpApp = value.toString() + + } + else { + super.onActivityResult(requestCode, resultCode, data) + } + } + + fun chooseDownApp(view: View) {chooseApp("downApp")} + fun chooseUpApp(view: View) {chooseApp("upApp")} + fun chooseLeftApp(view: View) {chooseApp("leftApp")} + fun chooseRightApp(view: View) {chooseApp("rightApp")} + fun chooseVolumeDownApp(view: View) {chooseApp("volumeDownApp")} + fun chooseVolumeUpApp(view: View) {chooseApp("volumeUpApp")} + + fun chooseApp(forAction :String) { + val intent = Intent(this, ChooseActivity::class.java) + intent.putExtra("action", "pick") // why choose an app + intent.putExtra("forApp", forAction) // which app we choose + startActivityForResult(intent, 5000) + } + + fun openNewTabWindow(urls: String, context : Context) { + val uris = Uri.parse(urls) + val intents = Intent(Intent.ACTION_VIEW, uris) + val b = Bundle() + b.putBoolean("new_window", true) + intents.putExtras(b) + context.startActivity(intents) + } + + fun openFinnWebsite(view: View) { + openNewTabWindow("https://www.finnmglas.com/", this) + } + + fun openGithubRepo(view: View) { + openNewTabWindow("https://github.com/finnmglas/Launcher", this) + } + + fun backHome(view: View) { + finish() + } + + // Show a dialog prompting for confirmation + fun resetSettingsClick(view: View) { + AlertDialog.Builder(this) + .setTitle("Reset Settings") + .setMessage("This will discard all your App Choices. Sure you want to continue?") + .setPositiveButton(android.R.string.yes, + DialogInterface.OnClickListener { dialog, which -> + resetSettings(this.getSharedPreferences(getString(R.string.preference_file_key), Context.MODE_PRIVATE)) + finish() + }) + .setNegativeButton(android.R.string.no, null) + .setIcon(android.R.drawable.ic_dialog_alert) + .show() + } + + @SuppressLint("SetTextI18n") // I do not care + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN) + window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) + + setContentView(R.layout.activity_settings) + } +} diff --git a/app/src/main/res/layout/activity_choose.xml b/app/src/main/res/layout/activity_choose.xml index 21cfda0..5183bf0 100644 --- a/app/src/main/res/layout/activity_choose.xml +++ b/app/src/main/res/layout/activity_choose.xml @@ -7,19 +7,33 @@ android:background="?attr/colorPrimaryDark" tools:context=".ChooseActivity"> + + + app:layout_constraintTop_toTopOf="@id/heading"> +