From 4e26fab27c2a797a7bdd43b7ba68bb15391804c4 Mon Sep 17 00:00:00 2001 From: lunaticbum <> Date: Wed, 14 Aug 2024 16:06:50 +0900 Subject: [PATCH] oh.... --- app/src/main/AndroidManifest.xml | 3 + .../rasel/lunar/launcher/apps/AppDrawer.kt | 204 +++-- .../rasel/lunar/launcher/apps/AppsAdapter.kt | 59 +- .../lunar/launcher/apps/ContactAdapter.kt | 131 ++++ .../rasel/lunar/launcher/apps/ContactMenu.kt | 438 +++++++++++ .../lunar/launcher/apps/SimpleGesture.kt | 705 ------------------ .../lunar/launcher/home/BatteryReceiver.kt | 9 +- .../rasel/lunar/launcher/home/LauncherHome.kt | 25 +- .../launcher/home/weather/WeatherExecutor.kt | 13 +- .../lunar/launcher/utils/MainActivity.kt | 78 ++ .../lunar/launcher/utils/SimpleGesture.kt | 55 +- .../lunar/launcher/view/CircleImageView.kt | 500 +++++++++++++ app/src/main/res/drawable/duckduckgo.xml | 27 + app/src/main/res/drawable/gmap.png | Bin 0 -> 10708 bytes app/src/main/res/drawable/google.png | Bin 0 -> 8181 bytes app/src/main/res/drawable/namuwiki.png | Bin 0 -> 33368 bytes app/src/main/res/drawable/naver.png | Bin 0 -> 4911 bytes app/src/main/res/drawable/navermap.png | Bin 0 -> 11933 bytes app/src/main/res/drawable/tmap.png | Bin 0 -> 7143 bytes app/src/main/res/layout/app_drawer.xml | 180 +++-- app/src/main/res/layout/apps_child.xml | 27 +- app/src/main/res/layout/contact_item.xml | 32 + app/src/main/res/values/attrs.xml | 9 + app/src/main/res/values/styles.xml | 15 +- 24 files changed, 1578 insertions(+), 932 deletions(-) create mode 100644 app/src/main/kotlin/rasel/lunar/launcher/apps/ContactAdapter.kt create mode 100644 app/src/main/kotlin/rasel/lunar/launcher/apps/ContactMenu.kt delete mode 100644 app/src/main/kotlin/rasel/lunar/launcher/apps/SimpleGesture.kt create mode 100644 app/src/main/kotlin/rasel/lunar/launcher/utils/MainActivity.kt create mode 100644 app/src/main/kotlin/rasel/lunar/launcher/view/CircleImageView.kt create mode 100644 app/src/main/res/drawable/duckduckgo.xml create mode 100644 app/src/main/res/drawable/gmap.png create mode 100644 app/src/main/res/drawable/google.png create mode 100644 app/src/main/res/drawable/namuwiki.png create mode 100644 app/src/main/res/drawable/naver.png create mode 100644 app/src/main/res/drawable/navermap.png create mode 100644 app/src/main/res/drawable/tmap.png create mode 100644 app/src/main/res/layout/contact_item.xml create mode 100644 app/src/main/res/values/attrs.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e30947b..b27a486 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -16,6 +16,7 @@ + @@ -38,6 +39,8 @@ android:excludeFromRecents="true" android:clearTaskOnLaunch="true" android:stateNotNeeded="true" + android:largeHeap="true" + android:hardwareAccelerated="true" android:screenOrientation="nosensor" android:windowSoftInputMode="adjustResize" android:requestLegacyExternalStorage="true"> diff --git a/app/src/main/kotlin/rasel/lunar/launcher/apps/AppDrawer.kt b/app/src/main/kotlin/rasel/lunar/launcher/apps/AppDrawer.kt index 23b0cc4..09ce3b5 100644 --- a/app/src/main/kotlin/rasel/lunar/launcher/apps/AppDrawer.kt +++ b/app/src/main/kotlin/rasel/lunar/launcher/apps/AppDrawer.kt @@ -19,15 +19,17 @@ package rasel.lunar.launcher.apps import android.annotation.SuppressLint +import android.content.ContentUris import android.content.Context import android.content.Intent import android.content.SharedPreferences import android.content.pm.PackageManager import android.content.pm.ResolveInfo -import android.graphics.Rect +import android.net.Uri import android.os.Build import android.os.Bundle -import android.provider.Settings.Global +import android.provider.ContactsContract +import android.util.Log import android.view.Gravity import android.view.LayoutInflater import android.view.View @@ -36,34 +38,24 @@ import android.view.View.VISIBLE import android.view.ViewGroup import android.view.inputmethod.InputMethodManager import androidx.appcompat.app.AlertDialog -import androidx.core.view.updateLayoutParams import androidx.core.widget.doOnTextChanged import androidx.fragment.app.Fragment import androidx.recyclerview.widget.GridLayoutManager -import androidx.recyclerview.widget.LinearLayoutManager -import com.google.android.material.textview.MaterialTextView import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.MainScope import kotlinx.coroutines.launch import rasel.lunar.launcher.BuildConfig import rasel.lunar.launcher.LauncherActivity.Companion.lActivity -import rasel.lunar.launcher.R import rasel.lunar.launcher.databinding.AppDrawerBinding -import rasel.lunar.launcher.helpers.Constants.Companion.DEFAULT_GRID_COLUMNS -import rasel.lunar.launcher.helpers.Constants.Companion.DEFAULT_SCROLLBAR_HEIGHT import rasel.lunar.launcher.helpers.Constants.Companion.KEY_APPS_COUNT import rasel.lunar.launcher.helpers.Constants.Companion.KEY_APPS_LAYOUT import rasel.lunar.launcher.helpers.Constants.Companion.KEY_DRAW_ALIGN -import rasel.lunar.launcher.helpers.Constants.Companion.KEY_GRID_COLUMNS import rasel.lunar.launcher.helpers.Constants.Companion.KEY_KEYBOARD_SEARCH import rasel.lunar.launcher.helpers.Constants.Companion.KEY_QUICK_LAUNCH -import rasel.lunar.launcher.helpers.Constants.Companion.KEY_SCROLLBAR_HEIGHT -import rasel.lunar.launcher.helpers.Constants.Companion.KEY_STATUS_BAR import rasel.lunar.launcher.helpers.Constants.Companion.PREFS_APP_NAMES import rasel.lunar.launcher.helpers.Constants.Companion.PREFS_SETTINGS import rasel.lunar.launcher.utils.BLog import java.text.Normalizer -import java.util.* import java.util.regex.Pattern @@ -77,6 +69,7 @@ internal class AppDrawer : Fragment() { companion object { private var packageManager: PackageManager? = null private var appsAdapter: AppsAdapter? = null + private var contactAdapter : ContactAdapter? = null private var packageInfoList: MutableList = mutableListOf() private var packageList = mutableListOf() @@ -84,11 +77,11 @@ internal class AppDrawer : Fragment() { // private val alphabetPattern = Pattern.compile("[A-Z]") @JvmStatic var settingsPrefs: SharedPreferences? = null @JvmStatic var appNamesPrefs: SharedPreferences? = null - // @JvmStatic var alphabetList = mutableListOf() - @JvmStatic var letterPreview: MaterialTextView? = null + private fun appName(resolver: ResolveInfo): String { if(appNamesPrefs?.contains(resolver.activityInfo.packageName) != null && appNamesPrefs?.getString(resolver.activityInfo.packageName,"")?.length ?: 0 > 0) { + BLog.LOGE("it.activityInfo.packageName >>>> ${resolver.activityInfo.packageName} == name : ${appNamesPrefs?.getString(resolver.activityInfo.packageName,"") ?: ""}") return appNamesPrefs?.getString(resolver.activityInfo.packageName,"") ?: "" } else { return resolver.loadLabel(packageManager).toString().apply { @@ -99,6 +92,7 @@ internal class AppDrawer : Fragment() { } } + fun getInputText() = binding.searchInput.text.toString() override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { binding = AppDrawerBinding.inflate(inflater, container, false) @@ -108,36 +102,106 @@ internal class AppDrawer : Fragment() { layoutType = settingsPrefs!!.getInt(KEY_APPS_LAYOUT, 0) packageManager = lActivity?.packageManager appsAdapter = AppsAdapter(layoutType, packageManager!!, childFragmentManager, binding.appsCount) - letterPreview = binding.appsCount + contactAdapter = ContactAdapter(packageManager!!, childFragmentManager) binding.appsCount.visibility = if (settingsPrefs!!.getBoolean(KEY_APPS_COUNT, true)) VISIBLE else GONE + binding.searchNmap.setOnClickListener { + openSearchApps("nmap://search?query=${getInputText()}&appname=${BuildConfig.APPLICATION_ID}","com.nhn.android.nmap") + } + binding.searchGoogleMap.setOnClickListener { + openSearchApps("geo:0,0?q=${getInputText()}","com.google.android.apps.maps") + } + binding.searchGoogle.setOnClickListener { + openSearchApps("https://www.google.com/search?q=${getInputText()}","com.android.chrome") + } + binding.searchTmap.setOnClickListener { + openSearchApps("tmap://search?name=${getInputText()}","com.skt.tmap.ku") + } + binding.searchNaver.setOnClickListener { + openSearchApps("https://search.naver.com/search.naver?where=nexearch&query=${getInputText()}", "com.nhn.android.search") + } + binding.searchDuckduckgo.setOnClickListener { + openSearchApps("https://duckduckgo.com/?t=h_&q=${getInputText()}","com.duckduckgo.mobile.android") + } + binding.searchNamuwiki.setOnClickListener { + openSearchApps("https://namu.wiki/Search?q=${getInputText()}") + } setLayout() - return binding.root } + + val originContactList = arrayListOf() + val contactList = arrayListOf() + private fun GetContact() { + if (originContactList.size > 0) { + + } else { + contactList.clear() + originContactList.clear() + val resolver = lActivity!!.contentResolver + + val phoneUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI + val projection = arrayOf( + ContactsContract.CommonDataKinds.Phone.CONTACT_ID, + ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, + ContactsContract.CommonDataKinds.Phone.NUMBER, + ) + + val cursor = resolver.query(phoneUri, projection, null, null, null) + if (cursor != null) { + while (cursor.moveToNext()) { + val idx =cursor.getColumnIndex(projection[0]) + val nameIndex = cursor.getColumnIndex(projection[1]) + val numberIndex = cursor.getColumnIndex(projection[2]) + var contactId = cursor.getString(idx) + val name = cursor.getString(nameIndex) + var number = cursor.getString(numberIndex) + number = number.replace("-", "") + if (name?.length ?: 0 > 0 && number?.length ?: 0 > 0) { + contactList.add(SimpleContact(contactId,name, number)) + originContactList.add(SimpleContact(contactId,name, number)) + } + Log.d("GetContact", "이름 : $name 번호 : $number ") + } + } + // 데이터 계열은 반드시 닫아줘야 한다. + cursor!!.close() + } + } + + + fun openSearchApps(schemeString : String, pakage : String? = null) { + val gmmIntentUri = Uri.parse(schemeString) + val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri) + pakage?.let { + mapIntent.setPackage(pakage) + } + startActivity(mapIntent) + } + @SuppressLint("ClickableViewAccessibility") override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - binding.reset.setOnClickListener { onResume() } + binding.reset.setOnClickListener { filterAppsList("") } - binding.moveDown.setOnClickListener { - binding.appsList.smoothScrollToPosition(packageList.size - 1) - } +// binding.moveDown.setOnClickListener { +// binding.appsList.smoothScrollToPosition(packageList.size - 1) +// } +// +// binding.moveUp.setOnClickListener { +// binding.appsList.smoothScrollToPosition(0) +// } - binding.moveUp.setOnClickListener { - binding.appsList.smoothScrollToPosition(0) - } - - binding.search.setOnClickListener { - when (isSearchShown) { - true -> closeSearch() - false -> openSearch() - } - } +// binding.search.setOnClickListener { +// when (isSearchShown) { +// true -> closeSearch() +// false -> openSearch() +// } +// } binding.searchInput.doOnTextChanged { inputText, _, _, _ -> binding.searchInput.text?.let { binding.searchInput.setSelection(it.length) } @@ -148,6 +212,7 @@ internal class AppDrawer : Fragment() { override fun onResume() { super.onResume() fetchApps() + GetContact() setKeyboardPadding() binding.appsCount.visibility = if (settingsPrefs!!.getBoolean(KEY_APPS_COUNT, true)) VISIBLE else GONE @@ -156,6 +221,8 @@ internal class AppDrawer : Fragment() { appsAdapter?.updateGravity(settingsPrefs!!.getInt(KEY_DRAW_ALIGN, Gravity.CENTER)) } + contactAdapter?.updateData(contactList) + /* pop up the keyboard */ if (settingsPrefs!!.getBoolean(KEY_KEYBOARD_SEARCH, false)) openSearch() } @@ -166,16 +233,18 @@ internal class AppDrawer : Fragment() { } private fun setLayout() { - when (layoutType) { - 0, 1 -> { - binding.appsList.layoutManager = LinearLayoutManager(requireContext()) - appsAdapter!!.updateGravity(settingsPrefs!!.getInt(KEY_DRAW_ALIGN, Gravity.CENTER)) - } - 2 -> binding.appsList.layoutManager = GridLayoutManager(requireContext(), Math.min(settingsPrefs!!.getInt(KEY_GRID_COLUMNS, DEFAULT_GRID_COLUMNS), 4)) - } - +// when (layoutType) { +// 0, 1 -> { +// binding.appsList.layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL,false) +// appsAdapter!!.updateGravity(settingsPrefs!!.getInt(KEY_DRAW_ALIGN, Gravity.CENTER)) +// } +// 2 -> binding.appsList.layoutManager = GridLayoutManager(requireContext(), Math.min(settingsPrefs!!.getInt(KEY_GRID_COLUMNS, DEFAULT_GRID_COLUMNS), 4), GridLayoutManager.HORIZONTAL,false) +// } + binding.appsList.layoutManager = GridLayoutManager(requireContext(), 2, GridLayoutManager.HORIZONTAL,false) + binding.contactList.layoutManager = GridLayoutManager(requireContext(), 2, GridLayoutManager.HORIZONTAL,false) /* initialize apps list adapter */ binding.appsList.adapter = appsAdapter + binding.contactList.adapter = contactAdapter } /* update app list with app and package name */ @@ -281,13 +350,25 @@ internal class AppDrawer : Fragment() { } else { appsAdapter?.updateData(packageList) } + contactList.clear() + for (item in originContactList) { + if (item.name.contains(searchString) || item.phoneNumber.contains(searchString)) { + contactList.add(item) + } + } + contactAdapter?.updateData(contactList) BLog.LOGE("END FILTER") } else if(lastSearchStringLength == 0){ + contactList.clear() + for (item in originContactList) { + contactList.add(item) + } packageList.clear() for (resolver in packageInfoList) { packageList.add(Packages(resolver.activityInfo.packageName, appName(resolver))) } appsAdapter?.updateData(packageList) + contactAdapter?.updateData(contactList) } lastSearchString = searchString lastSearchStringLength = searchString.length @@ -302,7 +383,6 @@ internal class AppDrawer : Fragment() { private fun openSearch() { isSearchShown = true - binding.search.setImageResource(R.drawable.ic_close) binding.searchInput.apply { visibility = VISIBLE requestFocus() @@ -316,7 +396,6 @@ internal class AppDrawer : Fragment() { /* clear search string, hide keyboard and search box */ private fun closeSearch() { isSearchShown = false - binding.search.setImageResource(R.drawable.ic_search) binding.searchInput.apply { text?.clear() visibility = GONE @@ -328,28 +407,29 @@ internal class AppDrawer : Fragment() { } private fun setKeyboardPadding() { - binding.root.viewTreeObserver.addOnGlobalLayoutListener { - val rect = Rect() - binding.root.getWindowVisibleDisplayFrame(rect) - val screenHeight = binding.root.height - val keyboardHeight = screenHeight - (rect.bottom - rect.top) - - when { - keyboardHeight > screenHeight * 0.15 -> { - if (!isKeyboardShowing && - !settingsPrefs!!.getBoolean(KEY_STATUS_BAR, false)) { - isKeyboardShowing = true - binding.root.setPadding(0, 0, 0, keyboardHeight) - } - } - else -> { - if (isKeyboardShowing) { - isKeyboardShowing = false - binding.root.setPadding(0, 0, 0, 0) - } - } - } - } +// binding.root.viewTreeObserver.addOnGlobalLayoutListener { +// val rect = Rect() +// binding.root.getWindowVisibleDisplayFrame(rect) +// val screenHeight = binding.root.height +// val keyboardHeight = screenHeight - (rect.bottom - rect.top) +// +// when { +// keyboardHeight > screenHeight * 0.15 -> { +// if (!isKeyboardShowing && +// !settingsPrefs!!.getBoolean(KEY_STATUS_BAR, false)) { +// isKeyboardShowing = true +// binding.root.setPadding(0, 0, 0, keyboardHeight) +// } +// } +// else -> { +// if (isKeyboardShowing) { +// isKeyboardShowing = false +// binding.root.setPadding(0, 0, 0, 0) +// } +// } +// } +// } } } + diff --git a/app/src/main/kotlin/rasel/lunar/launcher/apps/AppsAdapter.kt b/app/src/main/kotlin/rasel/lunar/launcher/apps/AppsAdapter.kt index 7da00b1..4a55523 100644 --- a/app/src/main/kotlin/rasel/lunar/launcher/apps/AppsAdapter.kt +++ b/app/src/main/kotlin/rasel/lunar/launcher/apps/AppsAdapter.kt @@ -25,6 +25,7 @@ import android.view.Gravity import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.TextView import androidx.core.view.updatePadding import androidx.fragment.app.FragmentManager import androidx.recyclerview.widget.DiffUtil @@ -43,7 +44,7 @@ internal class AppsAdapter( private val layoutType: Int, private val packageManager: PackageManager, private val fragmentManager: FragmentManager, - private val appsCount: MaterialTextView) : RecyclerView.Adapter() { + private val appsCount: TextView) : RecyclerView.Adapter() { private var oldList = mutableListOf() private var appGravity: Int = Gravity.CENTER @@ -57,57 +58,19 @@ internal class AppsAdapter( override fun onBindViewHolder(holder: AppsViewHolder, i: Int) { val item = oldList[i] - val fourDp = dpToPx(lActivity!!, R.dimen.four) - val eightDp = dpToPx(lActivity!!, R.dimen.eight) - val twelveDp = dpToPx(lActivity!!, R.dimen.twelve) - val sixteenDp = dpToPx(lActivity!!, R.dimen.sixteen) + holder.view.apply { childTextview.text = item.appName + appIconTwo.visibility = View.VISIBLE - when (layoutType) { - 0 -> { - appIcon.visibility = View.GONE - appIconTwo.visibility = View.GONE - childTextview.apply { - gravity = appGravity - setTextSize(TypedValue.COMPLEX_UNIT_PX, lActivity!!.resources.getDimension(R.dimen.twentyTwo)) - } - root.setPadding(sixteenDp, fourDp, sixteenDp, fourDp) - } - 1 -> { - appIcon.visibility = View.GONE - appIconTwo.visibility = View.VISIBLE - - MainScope().async { - getDrawableIconForPackage(item.packageName, packageManager.getApplicationIcon(item.packageName)) { - appIconTwo.post { appIconTwo.setImageDrawable(it) } - } } - - childTextview.apply { - gravity = appGravity or Gravity.CENTER_VERTICAL - setTextSize(TypedValue.COMPLEX_UNIT_PX, lActivity!!.resources.getDimension(R.dimen.twenty)) - updatePadding(left = twelveDp) - } - root.setPadding(sixteenDp, eightDp, sixteenDp, eightDp) - } - 2 -> { - appIconTwo.visibility = View.GONE - appIcon.visibility = View.VISIBLE - MainScope().async { - getDrawableIconForPackage( - item.packageName, - packageManager.getApplicationIcon(item.packageName) - ) { - appIcon.post { appIcon.setImageDrawable(it) } - } - } - childTextview.apply { - gravity = Gravity.CENTER - setTextSize(TypedValue.COMPLEX_UNIT_PX, lActivity!!.resources.getDimension(R.dimen.twelve)) - } - root.setPadding(eightDp, eightDp, eightDp, eightDp) - } + MainScope().async { + getDrawableIconForPackage(item.packageName, packageManager.getApplicationIcon(item.packageName)) { + appIconTwo.post { appIconTwo.setImageDrawable(it) } + } } + childTextview.apply { + gravity = Gravity.CENTER + setTextSize(TypedValue.COMPLEX_UNIT_PX, lActivity!!.resources.getDimension(R.dimen.twelve)) } } diff --git a/app/src/main/kotlin/rasel/lunar/launcher/apps/ContactAdapter.kt b/app/src/main/kotlin/rasel/lunar/launcher/apps/ContactAdapter.kt new file mode 100644 index 0000000..ea906fd --- /dev/null +++ b/app/src/main/kotlin/rasel/lunar/launcher/apps/ContactAdapter.kt @@ -0,0 +1,131 @@ +/* + * Lunar Launcher + * Copyright (C) 2022 Md Rasel Hossain + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package rasel.lunar.launcher.apps + +import android.annotation.SuppressLint +import android.content.Intent +import android.content.pm.PackageManager +import android.net.Uri +import android.util.TypedValue +import android.view.Gravity +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.core.view.updatePadding +import androidx.fragment.app.FragmentManager +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.RecyclerView +import com.google.android.material.textview.MaterialTextView +import kotlinx.coroutines.MainScope +import kotlinx.coroutines.async +import rasel.lunar.launcher.LauncherActivity.Companion.lActivity +import rasel.lunar.launcher.R +import rasel.lunar.launcher.apps.IconPackManager.Companion.getDrawableIconForPackage +import rasel.lunar.launcher.databinding.AppsChildBinding +import rasel.lunar.launcher.databinding.ContactItemBinding +import rasel.lunar.launcher.helpers.UniUtils.Companion.dpToPx +import rasel.lunar.launcher.utils.BLog + + +internal class ContactAdapter ( + private val packageManager: PackageManager, + private val fragmentManager: FragmentManager) : RecyclerView.Adapter() { + + private var oldList = mutableListOf() + private var appGravity: Int = Gravity.CENTER + + companion object { + @JvmStatic var appsSize: Int? = null + } + + override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): ContactViewHolder = + ContactViewHolder(ContactItemBinding.inflate(LayoutInflater.from(viewGroup.context), viewGroup, false)) + + override fun onBindViewHolder(holder: ContactViewHolder, i: Int) { + val item = oldList[i] + + + holder.view.apply { + name.text = item.name + number.text= item.phoneNumber + } + + holder.view.root.apply { + /* on click - open app */ + setOnClickListener { + context.startActivity(Intent(Intent.ACTION_CALL, Uri.parse("tel://${item.phoneNumber}"))) + } + + /* on long click - open app menu */ + setOnLongClickListener { + BLog.LOGE("item.id.toString() >> ${item.id.toString()}") + ContactMenu().show(fragmentManager, item.id.toString()) + true + } + } + } + + override fun getItemCount(): Int = oldList.size + + inner class ContactViewHolder(var view: ContactItemBinding) : RecyclerView.ViewHolder(view.root) + + /* update app list */ + fun updateData(newList: List) { + val diffUtilResult = DiffUtil.calculateDiff(ContactDiffUtil(oldList, newList)) + + oldList.clear() + oldList.addAll(newList) + diffUtilResult.dispatchUpdatesTo(this) + + newList.size.let { + appsSize = it + } + } + + /* update text gravity (alignment) */ + @SuppressLint("RtlHardcoded", "NotifyDataSetChanged") + fun updateGravity(gravity: Int){ + /* the first check is to avoid calling notifyDataSetChanged() everytime */ + if (gravity != appGravity && + (gravity == Gravity.LEFT || gravity == Gravity.CENTER || gravity == Gravity.RIGHT)) { + appGravity = gravity + notifyDataSetChanged() + } + } + + fun hideItem(idx: Int) { + + } +} +data class SimpleContact(val id : String,val name : String ,val phoneNumber : String) + +internal class ContactDiffUtil( + private val oldList: List, private val newList: List +) : DiffUtil.Callback() { + + override fun getOldListSize(): Int = oldList.size + override fun getNewListSize(): Int = newList.size + + override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean = + oldList[oldItemPosition].phoneNumber == newList[newItemPosition].phoneNumber + + override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean = + oldList[oldItemPosition] == newList[newItemPosition] +} diff --git a/app/src/main/kotlin/rasel/lunar/launcher/apps/ContactMenu.kt b/app/src/main/kotlin/rasel/lunar/launcher/apps/ContactMenu.kt new file mode 100644 index 0000000..233f46f --- /dev/null +++ b/app/src/main/kotlin/rasel/lunar/launcher/apps/ContactMenu.kt @@ -0,0 +1,438 @@ +/* + * Lunar Launcher + * Copyright (C) 2022 Md Rasel Hossain + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package rasel.lunar.launcher.apps + +import android.annotation.SuppressLint +import android.app.ActivityOptions +import android.content.ActivityNotFoundException +import android.content.ComponentName +import android.content.ContentUris +import android.content.Context +import android.content.Intent +import android.content.pm.ApplicationInfo +import android.content.pm.PackageManager +import android.content.res.ColorStateList +import android.graphics.Rect +import android.icu.text.SimpleDateFormat +import android.net.Uri +import android.os.Build +import android.os.Bundle +import android.provider.ContactsContract +import android.provider.Settings +import android.util.Log +import android.view.KeyEvent +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.inputmethod.InputMethodManager +import android.widget.AdapterView +import android.widget.ArrayAdapter +import android.widget.Toast +import androidx.appcompat.widget.LinearLayoutCompat +import androidx.core.content.FileProvider +import androidx.core.content.pm.PackageInfoCompat +import com.google.android.material.bottomsheet.BottomSheetDialog +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import com.google.android.material.button.MaterialButton +import com.google.android.material.button.MaterialButtonToggleGroup +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import rasel.lunar.launcher.LauncherActivity.Companion.lActivity +import rasel.lunar.launcher.R +import rasel.lunar.launcher.apps.AppDrawer.Companion.appNamesPrefs +import rasel.lunar.launcher.databinding.ActivityBrowserDialogBinding +import rasel.lunar.launcher.databinding.AppInfoDialogBinding +import rasel.lunar.launcher.databinding.AppMenuBinding +import rasel.lunar.launcher.helpers.Constants.Companion.KEY_APP_NO_ +import rasel.lunar.launcher.helpers.Constants.Companion.MAX_FAVORITE_APPS +import rasel.lunar.launcher.helpers.Constants.Companion.PREFS_FAVORITE_APPS +import rasel.lunar.launcher.helpers.UniUtils.Companion.copyToClipboard +import rasel.lunar.launcher.helpers.UniUtils.Companion.screenHeight +import rasel.lunar.launcher.helpers.UniUtils.Companion.screenWidth +import rasel.lunar.launcher.utils.BLog +import java.io.File +import java.io.FileInputStream +import java.io.FileOutputStream +import java.io.IOException +import java.util.* + + +internal class ContactMenu : BottomSheetDialogFragment() { + + private lateinit var binding: AppMenuBinding + private lateinit var packageName: String + private lateinit var packageManager: PackageManager + private lateinit var appInfo: ApplicationInfo + private lateinit var defAppName: String + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + binding = AppMenuBinding.inflate(inflater, container, false) + + /* get package name from fragment's tag */ + packageName = tag.toString() + val resolver = lActivity!!.contentResolver + val phoneUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI + val projection = arrayOf( + ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, + ContactsContract.CommonDataKinds.Phone.NUMBER, + ) + + BLog.LOGE("GetContact", "packageName ${packageName}") + val cursor = resolver.query(phoneUri, projection, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = " + packageName, null , null) + if (cursor != null) { + while (cursor.moveToNext()) { +// val idx =cursor.getColumnIndex(projection[0]) + val nameIndex = cursor.getColumnIndex(projection[0]) + val numberIndex = cursor.getColumnIndex(projection[1]) +// var contactId = cursor.getInt(idx) + val name = cursor.getString(nameIndex) + var number = cursor.getString(numberIndex) + number = number.replace("-", "") + BLog.LOGE("GetContact", "이름 : $name 번호 : $number ") + } + } + // 데이터 계열은 반드시 닫아줘야 한다. + cursor!!.close() + + /* get application info */ + + + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + (requireDialog() as BottomSheetDialog).dismissWithAnimation = true + + /* copy package name */ +// binding.appPackage.setOnClickListener { +// copyToClipboard(requireContext(), packageName) +// } +// +// appName() +// binding.detailedInfo.setOnClickListener { detailedInfo() } +// binding.activityBrowser.setOnClickListener { activityBrowser() } +// binding.appStore.setOnClickListener { appStore() } +// binding.appFreeform.setOnClickListener { freeform() } +// binding.appInfo.setOnClickListener { appInfo() } +// binding.appShare.setOnClickListener { share() } +// binding.appUninstall.setOnClickListener { uninstall() } + } + + /* manage initial preview and clicks for favorite apps */ + @SuppressLint("PrivateResource") + private fun favoriteApps() { + val sharedPreferences = requireContext().getSharedPreferences(PREFS_FAVORITE_APPS, 0) + val enabledStroke = + ColorStateList.valueOf(requireContext().getColor(com.google.android.material.R.color.material_on_surface_stroke)) + val disabledStroke = + ColorStateList.valueOf(requireContext().getColor(com.google.android.material.R.color.m3_chip_stroke_color)) + + for (position in 1..MAX_FAVORITE_APPS) { + val button = outlinedButton + val savedPackageName = sharedPreferences.getString(KEY_APP_NO_ + position, "") + + /* set previews */ + if (packageName == savedPackageName) button.isChecked = true + if (savedPackageName?.isNotEmpty() == true) button.strokeColor = enabledStroke + + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) + packageManager.getPackageInfo(savedPackageName!!, PackageManager.PackageInfoFlags.of(0)) + else + packageManager.getPackageInfo(savedPackageName!!, 0) + } catch (e: PackageManager.NameNotFoundException) { + requireContext().getSharedPreferences(PREFS_FAVORITE_APPS, 0) + .edit().remove(KEY_APP_NO_ + position).apply() + button.strokeColor = disabledStroke + e.printStackTrace() + } + + /* listen on clicks */ + binding.favGroup.addOnButtonCheckedListener { _: MaterialButtonToggleGroup?, + checkedId: Int, isChecked: Boolean -> + try { + if (checkedId == button.id) { + if (isChecked) { + requireContext().getSharedPreferences(PREFS_FAVORITE_APPS, 0) + .edit().putString(KEY_APP_NO_ + position, packageName).apply() + button.strokeColor = enabledStroke + } else { + requireContext().getSharedPreferences(PREFS_FAVORITE_APPS, 0) + .edit().remove(KEY_APP_NO_ + position).apply() + button.strokeColor = disabledStroke + } + } + } catch (e: Exception) { + e.printStackTrace() + } + } + } + } + + private fun appName() { + binding.appName.setOnFocusChangeListener { _, hasFocus -> + if (hasFocus) binding.appName.minWidth = resources.getDimensionPixelOffset(R.dimen.twoSeventySix) + else { + (requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager) + .hideSoftInputFromWindow(binding.appName.windowToken, 0) + + binding.appName.apply { + minWidth = resources.getDimensionPixelOffset(R.dimen.zero) + + if (text!!.isBlank()) setText(defAppName) + else setText(text!!.trim()) + + if (text.toString() == defAppName) appNamesPrefs?.edit()!!.remove(packageName).apply() + else appNamesPrefs?.edit()!!.putString(packageName, text.toString()).apply() + + (requireParentFragment() as AppDrawer).fetchApps() + } + } + } + + binding.appName.setOnKeyListener { _, keyCode, event -> + if (event.action == KeyEvent.ACTION_DOWN) { + if (keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_BACK) { + binding.appName.clearFocus() + return@setOnKeyListener true + } + } + false + } + } + + /* detailed info dialog */ + @SuppressLint("SetTextI18n") + private fun detailedInfo() { + val dialogBinding = AppInfoDialogBinding.inflate(lActivity!!.layoutInflater) + MaterialAlertDialogBuilder(lActivity!!) + .setView(dialogBinding.root) + .setPositiveButton(android.R.string.cancel, null) + .show() + + /* show app name */ + dialogBinding.appName.text = packageManager.getApplicationLabel(appInfo) + + /* get package info */ + val packageInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + packageManager.getPackageInfo(packageName, PackageManager.PackageInfoFlags.of(0)) + } else { + packageManager.getPackageInfo(packageName, 0) + } + + /* show infos */ + dialogBinding.mixed.text = + "${resources.getString(R.string.version)}: ${packageInfo.versionName} (${PackageInfoCompat.getLongVersionCode(packageInfo).toInt()})\n" + + "${resources.getString(R.string.sdk)}: ${appInfo.minSdkVersion} ~ ${appInfo.targetSdkVersion}\n" + + "${resources.getString(R.string.uid)}: ${appInfo.uid}\n" + + "${resources.getString(R.string.first_install)}: ${dateTimeFormat(packageInfo.firstInstallTime)}\n" + + "${resources.getString(R.string.last_update)}: ${dateTimeFormat(packageInfo.lastUpdateTime)}" + + /* show permissions */ + dialogBinding.permissions.text = permissionsList + } + + /* activity browser dialog */ + private fun activityBrowser() { + val dialogBinding = ActivityBrowserDialogBinding.inflate(lActivity!!.layoutInflater) + val dialogBuilder = MaterialAlertDialogBuilder(lActivity!!) + .setView(dialogBinding.root) + .setPositiveButton(android.R.string.cancel, null) + .show() + + /* show app name */ + dialogBinding.appName.text = packageManager.getApplicationLabel(appInfo) + + /* get activity info */ + val activityInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + packageManager.getPackageInfo( + packageName, PackageManager.PackageInfoFlags.of(PackageManager.GET_ACTIVITIES.toLong()) + ) + } else { + packageManager.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES) + } + + /* show activity list */ + val activityAdapter: ArrayAdapter = + ArrayAdapter(requireContext(), R.layout.list_item, R.id.itemText, ArrayList()) + if (activityInfo.activities.isNotEmpty()) { + for (activity in activityInfo.activities) { + activityAdapter.add( + activity.toString().split(" ").toTypedArray()[1].replace("}", "") + ) + } + dialogBinding.activityList.adapter = activityAdapter + } + + /* listen item clicks */ + dialogBinding.activityList.onItemClickListener = + AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, i: Int, _: Long -> + try { + /* open activity */ + val intent = Intent() + intent.component = ComponentName(packageName, activityAdapter.getItem(i).toString()) + intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK + requireContext().startActivity(intent) + } catch (exception: Exception) { + /* couldn't open activity */ + exception.printStackTrace() + val exceptionShort = (exception.toString().split(": ").toTypedArray())[0] + Toast.makeText(requireContext(), + "${resources.getString(R.string.unable_to_launch)} -\n$exceptionShort", Toast.LENGTH_LONG).show() + } + dialogBuilder.dismiss() + } + } + + /* open app's page in app store/market */ + private fun appStore() { + try { + val storeIntent = Intent(Intent.ACTION_VIEW) + storeIntent.data = Uri.parse("market://details?id=$packageName") + storeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + requireContext().startActivity(storeIntent) + } catch (activityNotFoundException: ActivityNotFoundException) { + /* no app store found exception */ + Toast.makeText(requireContext(), requireContext().getString(R.string.null_app_store_message), + Toast.LENGTH_SHORT).show() + activityNotFoundException.printStackTrace() + } + this.dismiss() + } + + /* launch app as a freeform window */ + private fun freeform() { + val freeformIntent = requireContext().packageManager.getLaunchIntentForPackage(packageName) + freeformIntent!!.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT or + Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK) + val rect = Rect(0, screenHeight / 2, screenWidth, screenHeight) + var activityOptions = activityOptions + activityOptions = activityOptions.setLaunchBounds(rect) + requireContext().startActivity(freeformIntent, activityOptions.toBundle()) + this.dismiss() + } + + /* open android's app info screen */ + private fun appInfo() { + val infoIntent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) + infoIntent.data = Uri.parse("package:$packageName") + infoIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + requireContext().startActivity(infoIntent) + this.dismiss() + } + + private fun share() { + try { + // Create a temporary file to copy the APK + val apkLabel = packageManager.getApplicationLabel(appInfo).toString().lowercase().replace(" ", "_") + val tempApkFile = File(requireContext().externalCacheDir, "$apkLabel.apk") + + // Copy the APK file + FileInputStream(File(appInfo.sourceDir)).use { `in` -> + FileOutputStream(tempApkFile).use { out -> + val buffer = ByteArray(1024) + var length: Int + while (`in`.read(buffer).also { length = it } > 0) { + out.write(buffer, 0, length) + } + } + } + + // Generate a content URI using FileProvider + val contentUri = + FileProvider.getUriForFile(requireContext(), "${requireContext().packageName}.fileprovider", tempApkFile) + + //requireContext().grantUriPermission(receivers.package.name, contentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION) + + // Create a Share Intent + Intent(Intent.ACTION_SEND).apply { + type = "application/vnd.android.package-archive" + putExtra(Intent.EXTRA_STREAM, contentUri) + addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + }.let { + // Start the chooser activity + startActivity(Intent.createChooser(it, getString(R.string.share_apk_message))) + } + } + catch (e: PackageManager.NameNotFoundException) { e.printStackTrace() } + catch (e: IOException) { e.printStackTrace() } + this.dismiss() + } + + /* uninstall the app */ + private fun uninstall() { + val uninstallIntent = Intent(Intent.ACTION_DELETE) + uninstallIntent.data = Uri.parse("package:$packageName") + uninstallIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK) + requireContext().startActivity(uninstallIntent) + this.dismiss() + } + + /* create and add an outlined button to the toggle group */ + private val outlinedButton: MaterialButton get() { + val style = com.google.android.material.R.attr.materialButtonOutlinedStyle + val button = MaterialButton(requireContext(), null, style) + button.layoutParams = LinearLayoutCompat.LayoutParams( + LinearLayoutCompat.LayoutParams.WRAP_CONTENT, + LinearLayoutCompat.LayoutParams.WRAP_CONTENT, 1F + ) + binding.favGroup.addView(button) + return button + } + + /* long value to local date-time format */ + private fun dateTimeFormat(long: Long) : String = SimpleDateFormat.getDateTimeInstance().format(Date(long)) + + /* get and arrange all the permissions for an application */ + private val permissionsList : String get() { + val packageInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + packageManager.getPackageInfo(packageName, PackageManager.PackageInfoFlags.of(PackageManager.GET_PERMISSIONS.toLong())) + } else { + packageManager.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS) + } + + return if (packageInfo.requestedPermissions.isNotEmpty()) { + val stringBuilder = StringBuilder() + packageInfo.requestedPermissions.indices.forEach { i: Int -> + if (i != packageInfo.requestedPermissions.size - 1) + stringBuilder.append("${packageInfo.requestedPermissions[i]}\n\n") + /* don't add any new line after the last entry */ + else + stringBuilder.append(packageInfo.requestedPermissions[i]) + } + stringBuilder.toString() + } else { + "" + } + } + + /* get activity options for launching app in freeform mode */ + private val activityOptions: ActivityOptions get() { + val activityOptions = ActivityOptions.makeBasic() + try { + val method = + ActivityOptions::class.java.getMethod("setLaunchWindowingMode", Int::class.javaPrimitiveType) + method.invoke(activityOptions, 5) + } catch (exception: Exception) { + exception.printStackTrace() + } + return activityOptions + } + +} diff --git a/app/src/main/kotlin/rasel/lunar/launcher/apps/SimpleGesture.kt b/app/src/main/kotlin/rasel/lunar/launcher/apps/SimpleGesture.kt deleted file mode 100644 index f5b8a66..0000000 --- a/app/src/main/kotlin/rasel/lunar/launcher/apps/SimpleGesture.kt +++ /dev/null @@ -1,705 +0,0 @@ -package rasel.lunar.launcher.apps - -import android.os.SystemClock -import android.util.Log -import android.view.MotionEvent -import android.view.View -import android.view.View.OnTouchListener -import kotlin.math.abs -import kotlin.math.pow -import kotlin.math.sqrt - -class GestureAnalyser @JvmOverloads constructor( - swipeSlopeIntolerance: Int = 3, - doubleTapMaxDelayMillis: Int = 500, - doubleTapMaxDownMillis: Int = 100 -) { - private val initialX = DoubleArray(5) - private val initialY = DoubleArray(5) - private val finalX = DoubleArray(5) - private val finalY = DoubleArray(5) - private val currentX = DoubleArray(5) - private val currentY = DoubleArray(5) - private val delX = DoubleArray(5) - private val delY = DoubleArray(5) - - private var numFingers = 0 - private var initialT: Long = 0 - private var finalT: Long = 0 - private var currentT: Long = 0 - - private var prevInitialT: Long = 0 - private var prevFinalT: Long = 0 - - private var swipeSlopeIntolerance = 3 - - private val doubleTapMaxDelayMillis: Long - private val doubleTapMaxDownMillis: Long - - init { - this.swipeSlopeIntolerance = swipeSlopeIntolerance - this.doubleTapMaxDownMillis = doubleTapMaxDownMillis.toLong() - this.doubleTapMaxDelayMillis = doubleTapMaxDelayMillis.toLong() - } - - fun trackGesture(ev: MotionEvent) { - val n = ev.pointerCount - for (i in 0 until n) { - initialX[i] = ev.getX(i).toDouble() - initialY[i] = ev.getY(i).toDouble() - } - numFingers = n - initialT = SystemClock.uptimeMillis() - } - - fun untrackGesture() { - numFingers = 0 - prevFinalT = SystemClock.uptimeMillis() - prevInitialT = initialT - } - - fun getGesture(ev: MotionEvent): GestureType { - var averageDistance = 0.0 - for (i in 0 until numFingers) { - finalX[i] = ev.getX(i).toDouble() - finalY[i] = ev.getY(i).toDouble() - delX[i] = finalX[i] - initialX[i] - delY[i] = finalY[i] - initialY[i] - - averageDistance += sqrt( - (finalX[i] - initialX[i]).pow(2.0) + (finalY[i] - initialY[i]).pow( - 2.0 - ) - ) - } - averageDistance /= numFingers.toDouble() - - finalT = SystemClock.uptimeMillis() - val gt = GestureType() - gt.gestureFlag = calcGesture() - gt.gestureDuration = finalT - initialT - gt.gestureDistance = averageDistance - return gt - } - - fun getOngoingGesture(ev: MotionEvent): Int { - for (i in 0 until numFingers) { - currentX[i] = ev.getX(i).toDouble() - currentY[i] = ev.getY(i).toDouble() - delX[i] = finalX[i] - initialX[i] - delY[i] = finalY[i] - initialY[i] - } - currentT = SystemClock.uptimeMillis() - return calcGesture() - } - - private fun calcGesture(): Int { - if (isDoubleTap) { - return DOUBLE_TAP_1 - } - - if (numFingers == 1) { - if ((-(delY[0])) > (swipeSlopeIntolerance * (abs( - delX[0] - ))) - ) { - return SWIPE_1_UP - } - - if (((delY[0])) > (swipeSlopeIntolerance * (abs( - delX[0] - ))) - ) { - return SWIPE_1_DOWN - } - - if ((-(delX[0])) > (swipeSlopeIntolerance * (abs( - delY[0] - ))) - ) { - return SWIPE_1_LEFT - } - - if (((delX[0])) > (swipeSlopeIntolerance * (abs( - delY[0] - ))) - ) { - return SWIPE_1_RIGHT - } - } - if (numFingers == 2) { - if (((-delY[0]) > (swipeSlopeIntolerance * abs( - delX[0] - ))) && ((-delY[1]) > (swipeSlopeIntolerance * abs( - delX[1] - ))) - ) { - return SWIPE_2_UP - } - if (((delY[0]) > (swipeSlopeIntolerance * abs( - delX[0] - ))) && ((delY[1]) > (swipeSlopeIntolerance * abs( - delX[1] - ))) - ) { - return SWIPE_2_DOWN - } - if (((-delX[0]) > (swipeSlopeIntolerance * abs( - delY[0] - ))) && ((-delX[1]) > (swipeSlopeIntolerance * abs( - delY[1] - ))) - ) { - return SWIPE_2_LEFT - } - if (((delX[0]) > (swipeSlopeIntolerance * abs( - delY[0] - ))) && ((delX[1]) > (swipeSlopeIntolerance * abs( - delY[1] - ))) - ) { - return SWIPE_2_RIGHT - } - if (finalFingDist(0, 1) > 2 * (initialFingDist(0, 1))) { - return UNPINCH_2 - } - if (finalFingDist(0, 1) < 0.5 * (initialFingDist(0, 1))) { - return PINCH_2 - } - } - if (numFingers == 3) { - if (((-delY[0]) > (swipeSlopeIntolerance * abs( - delX[0] - ))) - && ((-delY[1]) > (swipeSlopeIntolerance * abs( - delX[1] - ))) - && ((-delY[2]) > (swipeSlopeIntolerance * abs( - delX[2] - ))) - ) { - return SWIPE_3_UP - } - if (((delY[0]) > (swipeSlopeIntolerance * abs( - delX[0] - ))) - && ((delY[1]) > (swipeSlopeIntolerance * abs( - delX[1] - ))) - && ((delY[2]) > (swipeSlopeIntolerance * abs( - delX[2] - ))) - ) { - return SWIPE_3_DOWN - } - if (((-delX[0]) > (swipeSlopeIntolerance * abs( - delY[0] - ))) - && ((-delX[1]) > (swipeSlopeIntolerance * abs( - delY[1] - ))) - && ((-delX[2]) > (swipeSlopeIntolerance * abs( - delY[2] - ))) - ) { - return SWIPE_3_LEFT - } - if (((delX[0]) > (swipeSlopeIntolerance * abs( - delY[0] - ))) - && ((delX[1]) > (swipeSlopeIntolerance * abs( - delY[1] - ))) - && ((delX[2]) > (swipeSlopeIntolerance * abs( - delY[2] - ))) - ) { - return SWIPE_3_RIGHT - } - - if ((finalFingDist(0, 1) > 1.75 * (initialFingDist(0, 1))) - && (finalFingDist(1, 2) > 1.75 * (initialFingDist(1, 2))) - && (finalFingDist(2, 0) > 1.75 * (initialFingDist(2, 0))) - ) { - return UNPINCH_3 - } - if ((finalFingDist(0, 1) < 0.66 * (initialFingDist(0, 1))) - && (finalFingDist(1, 2) < 0.66 * (initialFingDist(1, 2))) - && (finalFingDist(2, 0) < 0.66 * (initialFingDist(2, 0))) - ) { - return PINCH_3 - } - } - if (numFingers == 4) { - if (((-delY[0]) > (swipeSlopeIntolerance * abs( - delX[0] - ))) - && ((-delY[1]) > (swipeSlopeIntolerance * abs( - delX[1] - ))) - && ((-delY[2]) > (swipeSlopeIntolerance * abs( - delX[2] - ))) - && ((-delY[3]) > (swipeSlopeIntolerance * abs( - delX[3] - ))) - ) { - return SWIPE_4_UP - } - if (((delY[0]) > (swipeSlopeIntolerance * abs( - delX[0] - ))) - && ((delY[1]) > (swipeSlopeIntolerance * abs( - delX[1] - ))) - && ((delY[2]) > (swipeSlopeIntolerance * abs( - delX[2] - ))) - && ((delY[3]) > (swipeSlopeIntolerance * abs( - delX[3] - ))) - ) { - return SWIPE_4_DOWN - } - if (((-delX[0]) > (swipeSlopeIntolerance * abs( - delY[0] - ))) - && ((-delX[1]) > (swipeSlopeIntolerance * abs( - delY[1] - ))) - && ((-delX[2]) > (swipeSlopeIntolerance * abs( - delY[2] - ))) - && ((-delX[3]) > (swipeSlopeIntolerance * abs( - delY[3] - ))) - ) { - return SWIPE_4_LEFT - } - if (((delX[0]) > (swipeSlopeIntolerance * abs( - delY[0] - ))) - && ((delX[1]) > (swipeSlopeIntolerance * abs( - delY[1] - ))) - && ((delX[2]) > (swipeSlopeIntolerance * abs( - delY[2] - ))) - && ((delX[3]) > (swipeSlopeIntolerance * abs( - delY[3] - ))) - ) { - return SWIPE_4_RIGHT - } - if ((finalFingDist(0, 1) > 1.5 * (initialFingDist(0, 1))) - && (finalFingDist(1, 2) > 1.5 * (initialFingDist(1, 2))) - && (finalFingDist(2, 3) > 1.5 * (initialFingDist(2, 3))) - && (finalFingDist(3, 0) > 1.5 * (initialFingDist(3, 0))) - ) { - return UNPINCH_4 - } - if ((finalFingDist(0, 1) < 0.8 * (initialFingDist(0, 1))) - && (finalFingDist(1, 2) < 0.8 * (initialFingDist(1, 2))) - && (finalFingDist(2, 3) < 0.8 * (initialFingDist(2, 3))) - && (finalFingDist(3, 0) < 0.8 * (initialFingDist(3, 0))) - ) { - return PINCH_4 - } - } - return 0 - } - - private fun initialFingDist(fingNum1: Int, fingNum2: Int): Double { - return sqrt( - (initialX[fingNum1] - initialX[fingNum2]).pow(2.0) + (initialY[fingNum1] - initialY[fingNum2]).pow( - 2.0 - ) - ) - } - - private fun finalFingDist(fingNum1: Int, fingNum2: Int): Double { - return sqrt( - (finalX[fingNum1] - finalX[fingNum2]).pow(2.0) + (finalY[fingNum1] - finalY[fingNum2]).pow( - 2.0 - ) - ) - } - - val isDoubleTap: Boolean - get() = if (initialT - prevFinalT < doubleTapMaxDelayMillis && finalT - initialT < doubleTapMaxDownMillis && prevFinalT - prevInitialT < doubleTapMaxDownMillis) { - true - } else { - false - } - - inner class GestureType { - var gestureFlag: Int = 0 - var gestureDuration: Long = 0 - - var gestureDistance: Double = 0.0 - } - - - companion object { - const val DEBUG: Boolean = true - - // Finished gestures flags - const val SWIPE_1_UP: Int = 11 - const val SWIPE_1_DOWN: Int = 12 - const val SWIPE_1_LEFT: Int = 13 - const val SWIPE_1_RIGHT: Int = 14 - const val SWIPE_2_UP: Int = 21 - const val SWIPE_2_DOWN: Int = 22 - const val SWIPE_2_LEFT: Int = 23 - const val SWIPE_2_RIGHT: Int = 24 - const val SWIPE_3_UP: Int = 31 - const val SWIPE_3_DOWN: Int = 32 - const val SWIPE_3_LEFT: Int = 33 - const val SWIPE_3_RIGHT: Int = 34 - const val SWIPE_4_UP: Int = 41 - const val SWIPE_4_DOWN: Int = 42 - const val SWIPE_4_LEFT: Int = 43 - const val SWIPE_4_RIGHT: Int = 44 - const val PINCH_2: Int = 25 - const val UNPINCH_2: Int = 26 - const val PINCH_3: Int = 35 - const val UNPINCH_3: Int = 36 - const val PINCH_4: Int = 45 - const val UNPINCH_4: Int = 46 - - const val DOUBLE_TAP_1: Int = 107 - - //Ongoing gesture flags - const val SWIPING_1_UP: Int = 101 - const val SWIPING_1_DOWN: Int = 102 - const val SWIPING_1_LEFT: Int = 103 - const val SWIPING_1_RIGHT: Int = 104 - const val SWIPING_2_UP: Int = 201 - const val SWIPING_2_DOWN: Int = 202 - const val SWIPING_2_LEFT: Int = 203 - const val SWIPING_2_RIGHT: Int = 204 - const val PINCHING: Int = 205 - const val UNPINCHING: Int = 206 - private const val TAG = "GestureAnalyser" - } -} - -class SimpleFingerGestures : OnTouchListener { - private var debug = true - var consumeTouchEvents: Boolean = false - - protected var tracking: BooleanArray = booleanArrayOf(false, false, false, false, false) - private var ga: GestureAnalyser - private var onFingerGestureListener: OnFingerGestureListener? = null - - - /** - * Constructor that creates an internal [in.championswimmer.sfg.lib.GestureAnalyser] object as well - */ - constructor() { - ga = GestureAnalyser() - } - - constructor( - swipeSlopeIntolerance: Int, - doubleTapMaxDelayMillis: Int, - doubleTapMaxDownMillis: Int - ) { - ga = GestureAnalyser(swipeSlopeIntolerance, doubleTapMaxDelayMillis, doubleTapMaxDownMillis) - } - - fun setDebug(debug: Boolean) { - this.debug = debug - } - - constructor(omfgl: OnFingerGestureListener?) { - ga = GestureAnalyser() - setOnFingerGestureListener(omfgl) - } - - /** - * Register a callback to be invoked when multi-finger gestures take place - * - * - *

- * - * - * For the callbacks implemented via this, check the interface [in.championswimmer.sfg.lib.SimpleFingerGestures.OnFingerGestureListener] - * - * - * @param omfgl The callback that will run - */ - fun setOnFingerGestureListener(omfgl: OnFingerGestureListener?) { - onFingerGestureListener = omfgl - } - - - override fun onTouch(view: View, ev: MotionEvent): Boolean { - if (debug) Log.d(TAG, "onTouch") - when (ev.action and MotionEvent.ACTION_MASK) { - MotionEvent.ACTION_DOWN -> { - if (debug) Log.d(TAG, "ACTION_DOWN") - startTracking(0) - ga.trackGesture(ev) - return consumeTouchEvents - } - - MotionEvent.ACTION_UP -> { - if (debug) Log.d(TAG, "ACTION_UP") - if (tracking[0]) { - doCallBack(ga.getGesture(ev)) - } - stopTracking(0) - ga.untrackGesture() - return consumeTouchEvents - } - - MotionEvent.ACTION_POINTER_DOWN -> { - if (debug) Log.d(TAG, "ACTION_POINTER_DOWN" + " " + "num" + ev.pointerCount) - startTracking(ev.pointerCount - 1) - ga.trackGesture(ev) - return consumeTouchEvents - } - - MotionEvent.ACTION_POINTER_UP -> { - if (debug) Log.d(TAG, "ACTION_POINTER_UP" + " " + "num" + ev.pointerCount) - if (tracking[1]) { - doCallBack(ga.getGesture(ev)) - } - stopTracking(ev.pointerCount - 1) - ga.untrackGesture() - return consumeTouchEvents - } - - MotionEvent.ACTION_CANCEL -> { - if (debug) Log.d(TAG, "ACTION_CANCEL") - return true - } - - MotionEvent.ACTION_MOVE -> { - if (debug) Log.d(TAG, "ACTION_MOVE") - return consumeTouchEvents - } - } - return consumeTouchEvents - } - - private fun doCallBack(mGt: GestureAnalyser.GestureType) { - when (mGt.gestureFlag) { - GestureAnalyser.SWIPE_1_UP -> onFingerGestureListener!!.onSwipeUp( - 1, - mGt.gestureDuration, - mGt.gestureDistance - ) - - GestureAnalyser.SWIPE_1_DOWN -> onFingerGestureListener!!.onSwipeDown( - 1, - mGt.gestureDuration, - mGt.gestureDistance - ) - - GestureAnalyser.SWIPE_1_LEFT -> onFingerGestureListener!!.onSwipeLeft( - 1, - mGt.gestureDuration, - mGt.gestureDistance - ) - - GestureAnalyser.SWIPE_1_RIGHT -> onFingerGestureListener!!.onSwipeRight( - 1, - mGt.gestureDuration, - mGt.gestureDistance - ) - - GestureAnalyser.SWIPE_2_UP -> onFingerGestureListener!!.onSwipeUp( - 2, - mGt.gestureDuration, - mGt.gestureDistance - ) - - GestureAnalyser.SWIPE_2_DOWN -> onFingerGestureListener!!.onSwipeDown( - 2, - mGt.gestureDuration, - mGt.gestureDistance - ) - - GestureAnalyser.SWIPE_2_LEFT -> onFingerGestureListener!!.onSwipeLeft( - 2, - mGt.gestureDuration, - mGt.gestureDistance - ) - - GestureAnalyser.SWIPE_2_RIGHT -> onFingerGestureListener!!.onSwipeRight( - 2, - mGt.gestureDuration, - mGt.gestureDistance - ) - - GestureAnalyser.PINCH_2 -> onFingerGestureListener!!.onPinch( - 2, - mGt.gestureDuration, - mGt.gestureDistance - ) - - GestureAnalyser.UNPINCH_2 -> onFingerGestureListener!!.onUnpinch( - 2, - mGt.gestureDuration, - mGt.gestureDistance - ) - - GestureAnalyser.SWIPE_3_UP -> onFingerGestureListener!!.onSwipeUp( - 3, - mGt.gestureDuration, - mGt.gestureDistance - ) - - GestureAnalyser.SWIPE_3_DOWN -> onFingerGestureListener!!.onSwipeDown( - 3, - mGt.gestureDuration, - mGt.gestureDistance - ) - - GestureAnalyser.SWIPE_3_LEFT -> onFingerGestureListener!!.onSwipeLeft( - 3, - mGt.gestureDuration, - mGt.gestureDistance - ) - - GestureAnalyser.SWIPE_3_RIGHT -> onFingerGestureListener!!.onSwipeRight( - 3, - mGt.gestureDuration, - mGt.gestureDistance - ) - - GestureAnalyser.PINCH_3 -> onFingerGestureListener!!.onPinch( - 3, - mGt.gestureDuration, - mGt.gestureDistance - ) - - GestureAnalyser.UNPINCH_3 -> onFingerGestureListener!!.onUnpinch( - 3, - mGt.gestureDuration, - mGt.gestureDistance - ) - - GestureAnalyser.SWIPE_4_UP -> onFingerGestureListener!!.onSwipeUp( - 4, - mGt.gestureDuration, - mGt.gestureDistance - ) - - GestureAnalyser.SWIPE_4_DOWN -> onFingerGestureListener!!.onSwipeDown( - 4, - mGt.gestureDuration, - mGt.gestureDistance - ) - - GestureAnalyser.SWIPE_4_LEFT -> onFingerGestureListener!!.onSwipeLeft( - 4, - mGt.gestureDuration, - mGt.gestureDistance - ) - - GestureAnalyser.SWIPE_4_RIGHT -> onFingerGestureListener!!.onSwipeRight( - 4, - mGt.gestureDuration, - mGt.gestureDistance - ) - - GestureAnalyser.PINCH_4 -> onFingerGestureListener!!.onPinch( - 4, - mGt.gestureDuration, - mGt.gestureDistance - ) - - GestureAnalyser.UNPINCH_4 -> { - onFingerGestureListener!!.onUnpinch(4, mGt.gestureDuration, mGt.gestureDistance) - onFingerGestureListener!!.onDoubleTap(1) - } - - GestureAnalyser.DOUBLE_TAP_1 -> onFingerGestureListener!!.onDoubleTap(1) - } - } - - private fun startTracking(nthPointer: Int) { - for (i in 0..nthPointer) { - tracking[i] = true - } - } - - private fun stopTracking(nthPointer: Int) { - for (i in nthPointer until tracking.size) { - tracking[i] = false - } - } - - - /** - * Interface definition for the callback to be invoked when 2-finger gestures are performed - */ - interface OnFingerGestureListener { - /** - * Called when user swipes **up** with two fingers - * - * @param fingers number of fingers involved in this gesture - * @param gestureDuration duration in milliSeconds - * @return - */ - fun onSwipeUp(fingers: Int, gestureDuration: Long, gestureDistance: Double): Boolean - - /** - * Called when user swipes **down** with two fingers - * - * @param fingers number of fingers involved in this gesture - * @param gestureDuration duration in milliSeconds - * @return - */ - fun onSwipeDown(fingers: Int, gestureDuration: Long, gestureDistance: Double): Boolean - - /** - * Called when user swipes **left** with two fingers - * - * @param fingers number of fingers involved in this gesture - * @param gestureDuration duration in milliSeconds - * @return - */ - fun onSwipeLeft(fingers: Int, gestureDuration: Long, gestureDistance: Double): Boolean - - /** - * Called when user swipes **right** with two fingers - * - * @param fingers number of fingers involved in this gesture - * @param gestureDuration duration in milliSeconds - * @return - */ - fun onSwipeRight(fingers: Int, gestureDuration: Long, gestureDistance: Double): Boolean - - /** - * Called when user **pinches** with two fingers (bring together) - * - * @param fingers number of fingers involved in this gesture - * @param gestureDuration duration in milliSeconds - * @return - */ - fun onPinch(fingers: Int, gestureDuration: Long, gestureDistance: Double): Boolean - - /** - * Called when user **un-pinches** with two fingers (take apart) - * - * @param fingers number of fingers involved in this gesture - * @param gestureDuration duration in milliSeconds - * @return - */ - fun onUnpinch(fingers: Int, gestureDuration: Long, gestureDistance: Double): Boolean - - fun onDoubleTap(fingers: Int): Boolean - } - - companion object { - // Will see if these need to be used. For now just returning duration in milliS - const val GESTURE_SPEED_SLOW: Long = 1500 - const val GESTURE_SPEED_MEDIUM: Long = 1000 - const val GESTURE_SPEED_FAST: Long = 500 - private const val TAG = "SimpleFingerGestures" - } -} \ No newline at end of file diff --git a/app/src/main/kotlin/rasel/lunar/launcher/home/BatteryReceiver.kt b/app/src/main/kotlin/rasel/lunar/launcher/home/BatteryReceiver.kt index a24b1fa..99e204e 100644 --- a/app/src/main/kotlin/rasel/lunar/launcher/home/BatteryReceiver.kt +++ b/app/src/main/kotlin/rasel/lunar/launcher/home/BatteryReceiver.kt @@ -43,16 +43,9 @@ internal class BatteryReceiver(private val progressBar: CircularProgressIndicato override fun onReceive(context: Context?, intent: Intent?) { val animationDuration = try { - intent?.extras?.keySet()?.let { - it.iterator().forEach { - BLog.LOGE("intent key >> ${it}") - } - } - BLog.LOGE("intent >> ${intent}") - Settings.Global.getFloat(context?.contentResolver, Settings.Global.ANIMATOR_DURATION_SCALE, 1.0f) } catch (e: Settings.SettingNotFoundException) { - e.printStackTrace() +// e.printStackTrace() } /* set battery percentage value to the circular progress bar */ diff --git a/app/src/main/kotlin/rasel/lunar/launcher/home/LauncherHome.kt b/app/src/main/kotlin/rasel/lunar/launcher/home/LauncherHome.kt index d9f838f..fbaee71 100644 --- a/app/src/main/kotlin/rasel/lunar/launcher/home/LauncherHome.kt +++ b/app/src/main/kotlin/rasel/lunar/launcher/home/LauncherHome.kt @@ -53,6 +53,7 @@ import rasel.lunar.launcher.qaccess.QuickAccess import rasel.lunar.launcher.settings.SettingsActivity import rasel.lunar.launcher.todos.TodoAdapter import rasel.lunar.launcher.todos.TodoManager +import rasel.lunar.launcher.utils.BLog import rasel.lunar.launcher.utils.SimpleFingerGestures import java.util.* @@ -216,7 +217,7 @@ internal class LauncherHome : Fragment() { return false } - override fun onLongPress(targetView: View): Boolean { + override fun onLongPress(targetView: View,fingers: Int): Boolean { if (view?.equals(binding.batteryProgress) ?: false) { lActivity!!.startActivity(Intent(requireContext(), SettingsActivity::class.java)) } else if (view?.equals(binding.notes) ?: false) { @@ -238,14 +239,24 @@ internal class LauncherHome : Fragment() { return false } - override fun onClick(targetView: View): Boolean { - if (view?.equals(binding.batteryProgress) ?: false) { - requireContext().startActivity( - Intent(AlarmClock.ACTION_SHOW_ALARMS).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - ) - } else if (view?.equals(binding.batteryProgress) ?: false) { + override fun onClick(targetView: View,fingers: Int): Boolean { + BLog.LOGE("onClick ${view} , fingers ${fingers}") + when(fingers) { + 1 -> { + if (view?.equals(binding.batteryProgress) ?: false && fingers == 1) { + requireContext().startActivity( + Intent(AlarmClock.ACTION_SHOW_ALARMS).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + ) + } + } + 2-> { + lockMethod(settingsPrefs.getInt(KEY_LOCK_METHOD, 0), requireContext(), binding.favAppsGroup) + } + else -> { + } } + return false } diff --git a/app/src/main/kotlin/rasel/lunar/launcher/home/weather/WeatherExecutor.kt b/app/src/main/kotlin/rasel/lunar/launcher/home/weather/WeatherExecutor.kt index 9e597e9..f2097af 100644 --- a/app/src/main/kotlin/rasel/lunar/launcher/home/weather/WeatherExecutor.kt +++ b/app/src/main/kotlin/rasel/lunar/launcher/home/weather/WeatherExecutor.kt @@ -37,6 +37,7 @@ internal class WeatherExecutor(sharedPreferences: SharedPreferences) { companion object { var lastedCheckTime = 0L + var weather: Weather? = null } private val cityName: String @@ -53,7 +54,6 @@ internal class WeatherExecutor(sharedPreferences: SharedPreferences) { if (System.currentTimeMillis() - lastedCheckTime > (1000 * 60 * 15) && isNetworkAvailable && cityName.isNotEmpty() && owmApi.isNotEmpty()) { try { Executors.newSingleThreadExecutor().execute { - var weather: Weather? = null WeatherClient().fetchWeather(weatherUrl).let { if (!it.isNullOrEmpty()) weather = JsonParser().getMyWeather(it) } @@ -72,6 +72,17 @@ internal class WeatherExecutor(sharedPreferences: SharedPreferences) { } catch (exception: Exception) { exception.printStackTrace() } + } else { + Handler(Looper.getMainLooper()).post { + if (weather != null) { + materialTextView.apply { + visibility = View.VISIBLE + text = weather!!.temperature.toString().substringBefore(".") + + (if (tempUnit == 0) "ºC" else "ºF") + + (if (showCity) " at ${weather!!.cityName}" else "") + } + } + } } lastedCheckTime = System.currentTimeMillis() } diff --git a/app/src/main/kotlin/rasel/lunar/launcher/utils/MainActivity.kt b/app/src/main/kotlin/rasel/lunar/launcher/utils/MainActivity.kt new file mode 100644 index 0000000..85dfd77 --- /dev/null +++ b/app/src/main/kotlin/rasel/lunar/launcher/utils/MainActivity.kt @@ -0,0 +1,78 @@ +//package com.example.ch16_provider +// +//import android.content.Intent +//import android.content.pm.PackageManager +//import android.os.Bundle +//import android.provider.ContactsContract +//import android.util.Log +//import androidx.activity.result.ActivityResultLauncher +//import androidx.activity.result.contract.ActivityResultContracts +//import androidx.appcompat.app.AppCompatActivity +//import androidx.core.app.ActivityCompat +//import androidx.core.content.ContextCompat +//import com.example.ch16_provider.databinding.ActivityMainBinding +// +//class MainActivity : AppCompatActivity() { +// lateinit var binding: ActivityMainBinding +// lateinit var requestLauncher: ActivityResultLauncher +// +// override fun onCreate(savedInstanceState: Bundle?) { +// super.onCreate(savedInstanceState) +// binding = ActivityMainBinding.inflate(layoutInflater) +// setContentView(binding.root) +// +// // 퍼미션 허용했는지 확인 +// val status = ContextCompat.checkSelfPermission(this, "android.permission.READ_CONTACTS") +// if (status == PackageManager.PERMISSION_GRANTED) { +// Log.d("test", "permission granted") +// } else { +// // 퍼미션 요청 다이얼로그 표시 +// ActivityCompat.requestPermissions(this, arrayOf("android.permission.READ_CONTACTS"), 100) +// Log.d("test", "permission denied") +// } +// +// // ActivityResultLauncher 초기화, 결과 콜백 정의 +// requestLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { +// if (it.resultCode == RESULT_OK) { +// Log.d("test", "Uri : ${it.data!!.data!!}") +// val cursor = contentResolver.query( +// it.data!!.data!!, +// arrayOf( +// ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, +// ContactsContract.CommonDataKinds.Phone.NUMBER, +// ), +// null, +// null, +// null +// ) +// Log.d("test", "cursor size : ${cursor?.count}") +// +// if (cursor!!.moveToFirst()) { +// val name = cursor.getString(0) +// val phone = cursor.getString(1) +// binding.textView.text = "name: $name, phone: $phone" +// } +// } +// } +// +// binding.button.setOnClickListener { +// // 주소록 앱 연동 +// val intent = Intent(Intent.ACTION_PICK, ContactsContract.CommonDataKinds.Phone.CONTENT_URI) +// requestLauncher.launch(intent) +// } +// } +// +// // 다이얼로그에서 퍼미션 허용했는지 확인 +// override fun onRequestPermissionsResult( +// requestCode: Int, +// permissions: Array, +// grantResults: IntArray +// ) { +// super.onRequestPermissionsResult(requestCode, permissions, grantResults) +// if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { +// Log.d("test", "permission granted") +// } else { +// Log.d("test", "permission denied") +// } +// } +//} \ No newline at end of file diff --git a/app/src/main/kotlin/rasel/lunar/launcher/utils/SimpleGesture.kt b/app/src/main/kotlin/rasel/lunar/launcher/utils/SimpleGesture.kt index 8019ea2..c42501f 100644 --- a/app/src/main/kotlin/rasel/lunar/launcher/utils/SimpleGesture.kt +++ b/app/src/main/kotlin/rasel/lunar/launcher/utils/SimpleGesture.kt @@ -133,7 +133,7 @@ class GestureAnalyser @JvmOverloads constructor( BLog.LOGE("initialT = ${initialT} , finalT = ${finalT} , result = ${finalT - initialT}") if (finalT - initialT < 300) { return CLICK_1 - } else if(finalT - initialT > 600) { + } else if(finalT - initialT > doubleTapMaxDelayMillis) { return LONG_CLICK_1 } } @@ -176,6 +176,11 @@ class GestureAnalyser @JvmOverloads constructor( if (finalFingDist(0, 1) < 0.5 * (initialFingDist(0, 1))) { return PINCH_2 } + if (finalT - initialT < 300) { + return CLICK_2 + } else if(finalT - initialT > doubleTapMaxDelayMillis) { + return LONG_CLICK_2 + } } if (numFingers == 3) { if (((-delY[0]) > (swipeSlopeIntolerance * abs( @@ -186,7 +191,7 @@ class GestureAnalyser @JvmOverloads constructor( ))) && ((-delY[2]) > (swipeSlopeIntolerance * abs( delX[2] - ))) + ))) && (abs(delY[0]) > minValue || abs(delY[1]) > minValue && abs(delY[2]) > minValue) ) { return SWIPE_3_UP } @@ -198,7 +203,7 @@ class GestureAnalyser @JvmOverloads constructor( ))) && ((delY[2]) > (swipeSlopeIntolerance * abs( delX[2] - ))) + ))) && (abs(delY[0]) > minValue || abs(delY[1]) > minValue && abs(delY[2]) > minValue) ) { return SWIPE_3_DOWN } @@ -210,7 +215,7 @@ class GestureAnalyser @JvmOverloads constructor( ))) && ((-delX[2]) > (swipeSlopeIntolerance * abs( delY[2] - ))) + ))) && (abs(delX[0]) > minValue || abs(delX[1]) > minValue && abs(delX[2]) > minValue) ) { return SWIPE_3_LEFT } @@ -222,7 +227,7 @@ class GestureAnalyser @JvmOverloads constructor( ))) && ((delX[2]) > (swipeSlopeIntolerance * abs( delY[2] - ))) + ))) && (abs(delX[0]) > minValue || abs(delX[1]) > minValue && abs(delX[2]) > minValue) ) { return SWIPE_3_RIGHT } @@ -239,6 +244,12 @@ class GestureAnalyser @JvmOverloads constructor( ) { return PINCH_3 } + + if (finalT - initialT < 300) { + return CLICK_3 + } else if(finalT - initialT > doubleTapMaxDelayMillis) { + return LONG_CLICK_3 + } } if (numFingers == 4) { if (((-delY[0]) > (swipeSlopeIntolerance * abs( @@ -424,8 +435,8 @@ class SimpleFingerGestures : OnTouchListener { ga.minValue = Math.max(screenHeight, 100) } this.onFingerGestureListener = onFingerGestureListener - this.targetView?.setOnClickListener { onFingerGestureListener.onClick(it) } - this.targetView?.setOnLongClickListener { onFingerGestureListener.onLongPress(it) } + this.targetView?.setOnClickListener { onFingerGestureListener.onClick(it,1) } + this.targetView?.setOnLongClickListener { onFingerGestureListener.onLongPress(it,1) } } /** * Constructor that creates an internal [in.championswimmer.sfg.lib.GestureAnalyser] object as well @@ -673,7 +684,17 @@ class SimpleFingerGestures : OnTouchListener { } GestureAnalyser.CLICK_1 -> { BLog.LOGE("GestureAnalyser.CLICK_1") - onFingerGestureListener!!.onClick(targetView) + onFingerGestureListener!!.onClick(targetView, 1) +// onFingerGestureListener!!.onDoubleTap(1) + } + GestureAnalyser.CLICK_2 -> { + BLog.LOGE("GestureAnalyser.CLICK_2") + onFingerGestureListener!!.onClick(targetView, 2) +// onFingerGestureListener!!.onDoubleTap(1) + } + GestureAnalyser.CLICK_3 -> { + BLog.LOGE("GestureAnalyser.CLICK_3") + onFingerGestureListener!!.onClick(targetView, 3) // onFingerGestureListener!!.onDoubleTap(1) } // GestureAnalyser.CLICK_2 -> { @@ -687,9 +708,16 @@ class SimpleFingerGestures : OnTouchListener { GestureAnalyser.LONG_CLICK_1 -> { BLog.LOGE("GestureAnalyser.LONG_CLICK_1") - onFingerGestureListener!!.onLongPress(targetView) + onFingerGestureListener!!.onLongPress(targetView,1) + } + GestureAnalyser.LONG_CLICK_2 -> { + BLog.LOGE("GestureAnalyser.LONG_CLICK_2") + onFingerGestureListener!!.onLongPress(targetView,2) + } + GestureAnalyser.LONG_CLICK_3 -> { + BLog.LOGE("GestureAnalyser.LONG_CLICK_3") + onFingerGestureListener!!.onLongPress(targetView,3) } - GestureAnalyser.DOUBLE_TAP_1 -> onFingerGestureListener!!.onDoubleTap(targetView,1) } @@ -767,8 +795,8 @@ class SimpleFingerGestures : OnTouchListener { fun onUnpinch(targetView : View,fingers: Int, gestureDuration: Long, gestureDistance: Double): Boolean fun onDoubleTap(targetView : View,fingers: Int): Boolean - fun onLongPress(targetView : View): Boolean - fun onClick(targetView : View): Boolean + fun onLongPress(targetView : View, fingers: Int): Boolean + fun onClick(targetView : View, fingers: Int): Boolean } companion object { @@ -778,4 +806,5 @@ class SimpleFingerGestures : OnTouchListener { const val GESTURE_SPEED_FAST: Long = 500 private const val TAG = "SimpleFingerGestures" } -} \ No newline at end of file +} + diff --git a/app/src/main/kotlin/rasel/lunar/launcher/view/CircleImageView.kt b/app/src/main/kotlin/rasel/lunar/launcher/view/CircleImageView.kt new file mode 100644 index 0000000..f0d1890 --- /dev/null +++ b/app/src/main/kotlin/rasel/lunar/launcher/view/CircleImageView.kt @@ -0,0 +1,500 @@ +package rasel.lunar.launcher.view + +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Bitmap +import android.graphics.BitmapShader +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.ColorFilter +import android.graphics.Matrix +import android.graphics.Outline +import android.graphics.Paint +import android.graphics.Rect +import android.graphics.RectF +import android.graphics.Shader +import android.graphics.drawable.BitmapDrawable +import android.graphics.drawable.ColorDrawable +import android.graphics.drawable.Drawable +import android.net.Uri +import android.os.Build +import android.util.AttributeSet +import android.view.MotionEvent +import android.view.View +import android.view.ViewOutlineProvider +import androidx.annotation.ColorRes +import androidx.annotation.DrawableRes +import androidx.annotation.NonNull +import androidx.annotation.RequiresApi +import rasel.lunar.launcher.R +import kotlin.math.min +import kotlin.math.pow + + +class CircleImageView : androidx.appcompat.widget.AppCompatImageView { + private val mDrawableRect = RectF() + private val mBorderRect = RectF() + + private val mShaderMatrix: Matrix = Matrix() + private val mBitmapPaint: Paint = Paint() + private val mBorderPaint: Paint = Paint() + private val mCircleBackgroundPaint: Paint = Paint() + + private var mBorderColor = DEFAULT_BORDER_COLOR + private var mBorderWidth = DEFAULT_BORDER_WIDTH + private var mCircleBackgroundColor = DEFAULT_CIRCLE_BACKGROUND_COLOR + private var mImageAlpha = DEFAULT_IMAGE_ALPHA + + private var mBitmap: Bitmap? = null + private var mBitmapCanvas: Canvas? = null + + private var mDrawableRadius = 0f + private var mBorderRadius = 0f + + private var mColorFilter: ColorFilter? = null + + private var mInitialized = false + private var mRebuildShader = false + private var mDrawableDirty = false + + private var mBorderOverlay = false + private var mDisableCircularTransformation = false + + constructor(context: Context) : super(context) { + init() + } + + @JvmOverloads + constructor(context: Context, attrs: AttributeSet?, defStyle: Int = 0) : super( + context, + attrs, + defStyle + ) { + val a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0) + + mBorderWidth = a.getDimensionPixelSize( + R.styleable.CircleImageView_civ_border_width, + DEFAULT_BORDER_WIDTH + ) + mBorderColor = + a.getColor(R.styleable.CircleImageView_civ_border_color, DEFAULT_BORDER_COLOR) + mBorderOverlay = + a.getBoolean(R.styleable.CircleImageView_civ_border_overlay, DEFAULT_BORDER_OVERLAY) + mCircleBackgroundColor = a.getColor( + R.styleable.CircleImageView_civ_circle_background_color, + DEFAULT_CIRCLE_BACKGROUND_COLOR + ) + + a.recycle() + + init() + } + + private fun init() { + mInitialized = true + + super.setScaleType(SCALE_TYPE) + + mBitmapPaint.setAntiAlias(true) + mBitmapPaint.setDither(true) + mBitmapPaint.setFilterBitmap(true) + mBitmapPaint.setAlpha(mImageAlpha) + mBitmapPaint.setColorFilter(mColorFilter) + + mBorderPaint.setStyle(Paint.Style.STROKE) + mBorderPaint.setAntiAlias(true) + mBorderPaint.setColor(mBorderColor) + mBorderPaint.setStrokeWidth(mBorderWidth.toFloat()) + + mCircleBackgroundPaint.setStyle(Paint.Style.FILL) + mCircleBackgroundPaint.setAntiAlias(true) + mCircleBackgroundPaint.setColor(mCircleBackgroundColor) + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + outlineProvider = OutlineProvider() + } + } + + override fun setScaleType(scaleType: ScaleType) { +// require(scaleType == SCALE_TYPE) { String.format("ScaleType %s not supported.", scaleType) } + super.setScaleType(scaleType) + } + + override fun setAdjustViewBounds(adjustViewBounds: Boolean) { +// require(!adjustViewBounds) { "adjustViewBounds not supported." } + super.setAdjustViewBounds(adjustViewBounds) + } + + @SuppressLint("CanvasSize") + override fun onDraw(canvas: Canvas) { + if (mDisableCircularTransformation) { + super.onDraw(canvas) + return + } + + if (mCircleBackgroundColor != Color.TRANSPARENT) { + canvas.drawCircle( + mDrawableRect.centerX(), + mDrawableRect.centerY(), + mDrawableRadius, + mCircleBackgroundPaint + ) + } + + if (mBitmap != null) { + if (mDrawableDirty && mBitmapCanvas != null) { + mDrawableDirty = false + val drawable = drawable + drawable.setBounds(0, 0, mBitmapCanvas!!.getWidth(), mBitmapCanvas!!.getHeight()) + drawable.draw(mBitmapCanvas!!) + } + + if (mRebuildShader) { + mRebuildShader = false + + val bitmapShader = + BitmapShader(mBitmap!!, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP) + bitmapShader.setLocalMatrix(mShaderMatrix) + + mBitmapPaint.setShader(bitmapShader) + } + + canvas.drawCircle( + mDrawableRect.centerX(), + mDrawableRect.centerY(), + mDrawableRadius, + mBitmapPaint + ) + } + + if (mBorderWidth > 0) { + canvas.drawCircle( + mBorderRect.centerX(), + mBorderRect.centerY(), + mBorderRadius, + mBorderPaint + ) + } + } + + override fun invalidateDrawable(@NonNull dr: Drawable) { + mDrawableDirty = true + invalidate() + } + + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + updateDimensions() + invalidate() + } + + override fun setPadding(left: Int, top: Int, right: Int, bottom: Int) { + super.setPadding(left, top, right, bottom) + updateDimensions() + invalidate() + } + + override fun setPaddingRelative(start: Int, top: Int, end: Int, bottom: Int) { + super.setPaddingRelative(start, top, end, bottom) + updateDimensions() + invalidate() + } + + var borderColor: Int + get() = mBorderColor + set(borderColor) { + if (borderColor == mBorderColor) { + return + } + + mBorderColor = borderColor + mBorderPaint.setColor(borderColor) + invalidate() + } + + var circleBackgroundColor: Int + get() = mCircleBackgroundColor + set(circleBackgroundColor) { + if (circleBackgroundColor == mCircleBackgroundColor) { + return + } + + mCircleBackgroundColor = circleBackgroundColor + mCircleBackgroundPaint.setColor(circleBackgroundColor) + invalidate() + } + + + @Deprecated("Use {@link #setCircleBackgroundColor(int)} instead") + fun setCircleBackgroundColorResource(@ColorRes circleBackgroundRes: Int) { + circleBackgroundColor = context.resources.getColor(circleBackgroundRes) + } + + var borderWidth: Int + get() = mBorderWidth + set(borderWidth) { + if (borderWidth == mBorderWidth) { + return + } + + mBorderWidth = borderWidth + mBorderPaint.setStrokeWidth(borderWidth.toFloat()) + updateDimensions() + invalidate() + } + + var isBorderOverlay: Boolean + get() = mBorderOverlay + set(borderOverlay) { + if (borderOverlay == mBorderOverlay) { + return + } + + mBorderOverlay = borderOverlay + updateDimensions() + invalidate() + } + + var isDisableCircularTransformation: Boolean + get() = mDisableCircularTransformation + set(disableCircularTransformation) { + if (disableCircularTransformation == mDisableCircularTransformation) { + return + } + + mDisableCircularTransformation = disableCircularTransformation + + if (disableCircularTransformation) { + mBitmap = null + mBitmapCanvas = null + mBitmapPaint.setShader(null) + } else { + initializeBitmap() + } + + invalidate() + } + + override fun setImageBitmap(bm: Bitmap) { + super.setImageBitmap(bm) + initializeBitmap() + invalidate() + } + + override fun setImageDrawable(drawable: Drawable?) { + super.setImageDrawable(drawable) + initializeBitmap() + invalidate() + } + + override fun setImageResource(@DrawableRes resId: Int) { + super.setImageResource(resId) + initializeBitmap() + invalidate() + } + + override fun setImageURI(uri: Uri?) { + super.setImageURI(uri) + initializeBitmap() + invalidate() + } + + override fun setImageAlpha(alpha: Int) { + var alpha = alpha + alpha = alpha and 0xFF + + if (alpha == mImageAlpha) { + return + } + + mImageAlpha = alpha + + // This might be called during ImageView construction before + // member initialization has finished on API level >= 16. + if (mInitialized) { + mBitmapPaint.setAlpha(alpha) + invalidate() + } + } + + override fun getImageAlpha(): Int { + return mImageAlpha + } + + override fun setColorFilter(cf: ColorFilter) { + if (cf === mColorFilter) { + return + } + + mColorFilter = cf + + // This might be called during ImageView construction before + // member initialization has finished on API level <= 19. + if (mInitialized) { + mBitmapPaint.setColorFilter(cf) + invalidate() + } + } + + override fun getColorFilter(): ColorFilter { + return mColorFilter ?: ColorFilter() + } + + private fun getBitmapFromDrawable(drawable: Drawable?): Bitmap? { + if (drawable == null) { + return null + } + + if (drawable is BitmapDrawable) { + return drawable.bitmap + } + + try { + val bitmap = if (drawable is ColorDrawable) { + Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG) + } else { + Bitmap.createBitmap( + drawable.intrinsicWidth, + drawable.intrinsicHeight, + BITMAP_CONFIG + ) + } + + val canvas: Canvas = Canvas(bitmap) + drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()) + drawable.draw(canvas) + return bitmap + } catch (e: java.lang.Exception) { + e.printStackTrace() + return null + } + } + + private fun initializeBitmap() { + mBitmap = getBitmapFromDrawable(drawable) + + if (mBitmap != null && mBitmap!!.isMutable) { + mBitmapCanvas = Canvas(mBitmap!!) + } else { + mBitmapCanvas = null + } + + if (!mInitialized) { + return + } + + if (mBitmap != null) { + updateShaderMatrix() + } else { + mBitmapPaint.setShader(null) + } + } + + private fun updateDimensions() { + mBorderRect.set(calculateBounds()) + mBorderRadius = min( + ((mBorderRect.height() - mBorderWidth) / 2.0f).toDouble(), + ((mBorderRect.width() - mBorderWidth) / 2.0f).toDouble() + ) + .toFloat() + + mDrawableRect.set(mBorderRect) + if (!mBorderOverlay && mBorderWidth > 0) { + mDrawableRect.inset(mBorderWidth - 1.0f, mBorderWidth - 1.0f) + } + mDrawableRadius = min( + (mDrawableRect.height() / 2.0f).toDouble(), + (mDrawableRect.width() / 2.0f).toDouble() + ) + .toFloat() + + updateShaderMatrix() + } + + private fun calculateBounds(): RectF { + val availableWidth = width - paddingLeft - paddingRight + val availableHeight = height - paddingTop - paddingBottom + + val sideLength = + min(availableWidth.toDouble(), availableHeight.toDouble()).toInt() + + val left = paddingLeft + (availableWidth - sideLength) / 2f + val top = paddingTop + (availableHeight - sideLength) / 2f + + return RectF(left, top, left + sideLength, top + sideLength) + } + + private fun updateShaderMatrix() { + if (mBitmap == null) { + return + } + + val scale: Float + var dx = 0f + var dy = 0f + + mShaderMatrix.set(null) + + val bitmapHeight = mBitmap!!.height + val bitmapWidth = mBitmap!!.width + + if (bitmapWidth * mDrawableRect.height() > mDrawableRect.width() * bitmapHeight) { + scale = mDrawableRect.height() / bitmapHeight.toFloat() + dx = (mDrawableRect.width() - bitmapWidth * scale) * 0.5f + } else { + scale = mDrawableRect.width() / bitmapWidth.toFloat() + dy = (mDrawableRect.height() - bitmapHeight * scale) * 0.5f + } + + mShaderMatrix.setScale(scale, scale) + mShaderMatrix.postTranslate( + (dx + 0.5f).toInt() + mDrawableRect.left, + (dy + 0.5f).toInt() + mDrawableRect.top + ) + + mRebuildShader = true + } + + @SuppressLint("ClickableViewAccessibility") + override fun onTouchEvent(event: MotionEvent): Boolean { + if (mDisableCircularTransformation) { + return super.onTouchEvent(event) + } + + return inTouchableArea(event.x, event.y) && super.onTouchEvent(event) + } + + private fun inTouchableArea(x: Float, y: Float): Boolean { + if (mBorderRect.isEmpty) { + return true + } + + return (x - mBorderRect.centerX()).pow(2.0F) + (y - mBorderRect.centerY()).pow(2.0F) <= mBorderRadius.pow(2.0F) + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + private inner class OutlineProvider : ViewOutlineProvider() { + override fun getOutline(view: View?, outline: Outline) { + if (mDisableCircularTransformation) { + BACKGROUND.getOutline(view, outline) + } else { + val bounds: Rect = Rect() + mBorderRect.roundOut(bounds) + outline.setRoundRect(bounds, bounds.width() / 2.0f) + } + } + } + + companion object { + private val SCALE_TYPE = ScaleType.CENTER_CROP + + private val BITMAP_CONFIG = Bitmap.Config.ARGB_8888 + private const val COLORDRAWABLE_DIMENSION = 2 + + private const val DEFAULT_BORDER_WIDTH = 0 + private val DEFAULT_BORDER_COLOR: Int = Color.BLACK + private val DEFAULT_CIRCLE_BACKGROUND_COLOR: Int = Color.TRANSPARENT + private const val DEFAULT_IMAGE_ALPHA = 255 + private const val DEFAULT_BORDER_OVERLAY = false + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/duckduckgo.xml b/app/src/main/res/drawable/duckduckgo.xml new file mode 100644 index 0000000..eefd78f --- /dev/null +++ b/app/src/main/res/drawable/duckduckgo.xml @@ -0,0 +1,27 @@ + + + + + + + + + diff --git a/app/src/main/res/drawable/gmap.png b/app/src/main/res/drawable/gmap.png new file mode 100644 index 0000000000000000000000000000000000000000..8543444cad95c4fac58143e8c80ccc041aa634c8 GIT binary patch literal 10708 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

v=+1!DL;Kl- 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/naver.png b/app/src/main/res/drawable/naver.png new file mode 100644 index 0000000000000000000000000000000000000000..8a3a31f4492a9f5ccf3c8169589a2a31f7b8d1d9 GIT binary patch literal 4911 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/navermap.png b/app/src/main/res/drawable/navermap.png new file mode 100644 index 0000000000000000000000000000000000000000..2829b03d387b397383e5bb7c00e341db04c75863 GIT binary patch literal 11933 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 Cks`|g literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/tmap.png b/app/src/main/res/drawable/tmap.png new file mode 100644 index 0000000000000000000000000000000000000000..f20ca6e87f72e028fb75cc86f0ab148390e027fb GIT binary patch literal 7143 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/layout/app_drawer.xml b/app/src/main/res/layout/app_drawer.xml index e85e2c9..99ee65a 100644 --- a/app/src/main/res/layout/app_drawer.xml +++ b/app/src/main/res/layout/app_drawer.xml @@ -3,43 +3,114 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" + android:layout_height="match_parent"> - - - - - - - - - - - - - + android:layout_width="0dp" + android:layout_height="0dp"> + + + + + + + + + + + + + + + + + + - - - - - - + app:layout_constraintRight_toLeftOf="@id/reset"/> + diff --git a/app/src/main/res/layout/apps_child.xml b/app/src/main/res/layout/apps_child.xml index 25c3e25..173f7f0 100644 --- a/app/src/main/res/layout/apps_child.xml +++ b/app/src/main/res/layout/apps_child.xml @@ -1,39 +1,32 @@ + /> - - diff --git a/app/src/main/res/layout/contact_item.xml b/app/src/main/res/layout/contact_item.xml new file mode 100644 index 0000000..ed64938 --- /dev/null +++ b/app/src/main/res/layout/contact_item.xml @@ -0,0 +1,32 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml new file mode 100644 index 0000000..ff8702d --- /dev/null +++ b/app/src/main/res/values/attrs.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index ed2bb2c..46c24b8 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,5 +1,5 @@ - + + + + + \ No newline at end of file