├── .gitattributes ├── .gitignore ├── Play Store ├── Play_icon.png ├── Screenshot3.jpg ├── Screenshot4.jpg ├── Screenshot_2015-07-05-23-48-23.png ├── Screenshot_2015-07-05-23-48-35.png └── Screenshot_20160321-072345.png ├── README.md ├── app ├── build.gradle.kts ├── lint.xml ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── ic_launcher-web.png │ ├── ic_multitool-web.png │ ├── ic_next-web.png │ ├── ic_play-web.png │ ├── ic_previous-web.png │ ├── java │ └── com │ │ └── faendir │ │ └── lightning_launcher │ │ └── multitool │ │ ├── Loader.kt │ │ ├── MainActivity.kt │ │ ├── MultiTool.kt │ │ ├── animation │ │ ├── Animation.kt │ │ ├── AnimationDemo.kt │ │ ├── AnimationFragment.kt │ │ ├── AnimationScript.kt │ │ ├── PointB.kt │ │ ├── Size.kt │ │ └── Transformation.kt │ │ ├── backup │ │ ├── BackupCreator.kt │ │ ├── BackupFragment.kt │ │ ├── BackupJob.kt │ │ ├── BackupTime.kt │ │ ├── BackupTimePreference.kt │ │ └── BackupUtils.kt │ │ ├── badge │ │ ├── AppChooser.kt │ │ ├── BadgeBroadcastReceiver.kt │ │ ├── BadgeDataSource.kt │ │ ├── BadgeFragment.kt │ │ ├── BadgeListener.kt │ │ ├── BadgeNotificationListener.kt │ │ └── BadgeSetup.kt │ │ ├── billing │ │ ├── BaseBillingManager.kt │ │ └── BillingManager.kt │ │ ├── calendar │ │ ├── CalendarDataSource.kt │ │ ├── CalendarFragment.kt │ │ ├── CalendarPreference.kt │ │ └── CalendarScript.kt │ │ ├── drawer │ │ ├── Drawer.kt │ │ ├── DrawerFragment.kt │ │ └── RestorePreference.kt │ │ ├── event │ │ ├── ClickEvent.kt │ │ └── SwitchFragmentRequest.kt │ │ ├── fastadapter │ │ ├── ClickAwareModel.kt │ │ ├── DeletableModel.kt │ │ ├── ExpandableItem.kt │ │ ├── ItemFactory.kt │ │ └── Model.kt │ │ ├── gesture │ │ ├── GestureActivity.kt │ │ ├── GestureFragment.kt │ │ ├── GestureInfo.kt │ │ ├── GestureLibraryDataSource.kt │ │ ├── GestureMetaDataSource.kt │ │ ├── GestureScript.kt │ │ ├── GestureUtils.kt │ │ ├── IntentChooser.kt │ │ ├── LightningGestureView.kt │ │ └── SingleStoreGestureLibrary.kt │ │ ├── immersive │ │ └── ImmersiveScript.kt │ │ ├── launcherscript │ │ ├── Action.kt │ │ ├── ActionGroup.kt │ │ ├── LauncherScriptFragment.kt │ │ └── MultiToolScript.kt │ │ ├── music │ │ ├── MusicDataSource.kt │ │ ├── MusicFragment.kt │ │ ├── MusicListener.kt │ │ ├── MusicNotificationListener.kt │ │ ├── MusicSetup.kt │ │ └── TitleInfo.kt │ │ ├── proxy │ │ ├── ActivityScreen.kt │ │ ├── Box.kt │ │ ├── Container.kt │ │ ├── CustomView.kt │ │ ├── Desktop.kt │ │ ├── Event.kt │ │ ├── EventHandler.kt │ │ ├── Folder.kt │ │ ├── Function.kt │ │ ├── Image.kt │ │ ├── ImageBitmap.kt │ │ ├── Item.kt │ │ ├── JavaScript.kt │ │ ├── Lightning.kt │ │ ├── Menu.kt │ │ ├── Panel.kt │ │ ├── PropertyEditor.kt │ │ ├── PropertySet.kt │ │ ├── Proxy.kt │ │ ├── ProxyFactory.kt │ │ ├── RectL.kt │ │ ├── Screen.kt │ │ ├── Script.kt │ │ ├── Scriptable.kt │ │ ├── Shortcut.kt │ │ ├── Utils.kt │ │ ├── VariableEditor.kt │ │ └── VariableSet.kt │ │ ├── scriptmanager │ │ ├── Folder.kt │ │ ├── FormatTask3.kt │ │ ├── ListManager.kt │ │ ├── Script.kt │ │ ├── ScriptManagerFragment.kt │ │ └── ScriptUtils.kt │ │ ├── settings │ │ ├── DefaultPlayerPreference.kt │ │ ├── HasPlayerEntries.kt │ │ ├── IdPreference.kt │ │ ├── PlayersPreference.kt │ │ ├── PreferenceListener.kt │ │ ├── PrefsFragment.kt │ │ ├── SummaryPreference.kt │ │ ├── TrialPreference.kt │ │ └── VersionPreference.kt │ │ └── util │ │ ├── BaseActivity.kt │ │ ├── DrawableProvider.kt │ │ ├── FragmentManager.kt │ │ ├── Fragments.kt │ │ ├── IntentChooserFragment.kt │ │ ├── IntentHandlerListTask.kt │ │ ├── IntentInfo.kt │ │ ├── LightningObjectFactory.kt │ │ ├── ReflectionJobCreator.kt │ │ ├── ResetReportPrimer.kt │ │ ├── ResolveInfoDrawableProvider.kt │ │ ├── ScriptBuilder.kt │ │ ├── SetupDistributor.kt │ │ ├── Utils.kt │ │ ├── notification │ │ ├── NotificationDistributorService.kt │ │ └── NotificationListener.kt │ │ ├── provider │ │ ├── BaseContentListener.kt │ │ ├── DataProvider.kt │ │ ├── DataSource.kt │ │ ├── FileDataSource.kt │ │ ├── QueryDataSource.kt │ │ ├── RemoteSharedPreferences.kt │ │ ├── SharedPreferencesDataSource.kt │ │ └── UpdateDataSource.kt │ │ └── view │ │ └── CanDisableTimePicker.kt │ └── res │ ├── color │ └── timepicker_text_color.xml │ ├── drawable-hdpi │ ├── ic_next.png │ ├── ic_play.png │ └── ic_previous.png │ ├── drawable-mdpi │ ├── ic_next.png │ ├── ic_play.png │ └── ic_previous.png │ ├── drawable-xhdpi │ ├── ic_next.png │ ├── ic_play.png │ └── ic_previous.png │ ├── drawable-xxhdpi │ ├── ic_next.png │ ├── ic_play.png │ └── ic_previous.png │ ├── drawable-xxxhdpi │ ├── ic_next.png │ ├── ic_play.png │ └── ic_previous.png │ ├── drawable │ ├── animation_demo.xml │ ├── animation_demo_flipped.xml │ ├── ic_add_white.xml │ ├── ic_arrow_drop_down_white.xml │ ├── ic_delete_white.xml │ ├── ic_edit_white.xml │ ├── ic_file_white.xml │ ├── ic_folder_white.xml │ ├── ic_help_white.xml │ ├── ic_mode_edit_white.xml │ ├── ic_search_white.xml │ ├── ic_sort_white.xml │ └── round_button.xml │ ├── layout-land │ └── fragment_animation.xml │ ├── layout │ ├── activity_base.xml │ ├── content_app_chooser.xml │ ├── content_gesture.xml │ ├── content_intent_chooser.xml │ ├── content_main.xml │ ├── fragment_animation.xml │ ├── fragment_launcher_script.xml │ ├── fragment_loading.xml │ ├── fragment_music.xml │ ├── intent_chooser_page.xml │ ├── list_item_app.xml │ ├── preference_backup_time.xml │ └── textview_empty_gestures_list.xml │ ├── menu │ ├── animation.xml │ ├── backup.xml │ ├── badge.xml │ ├── menu_badge_app_chooser.xml │ ├── menu_context_scriptmanager.xml │ ├── menu_gesture.xml │ ├── menu_music_widget.xml │ ├── menu_scriptmanager.xml │ └── menu_search.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ ├── ic_launcher_foreground.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ ├── ic_launcher_foreground.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ ├── ic_launcher_foreground.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ ├── ic_launcher_foreground.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ ├── ic_launcher_foreground.png │ └── ic_launcher_round.png │ ├── raw │ ├── activity_result.js │ ├── command.js │ ├── create_view.js │ ├── direct.js │ ├── library.js │ ├── menu.js │ ├── multitool.js │ ├── normal.js │ ├── register.js │ ├── setup.js │ └── unregister.js │ ├── values-w820dp │ └── dimens.xml │ ├── values │ ├── attrs.xml │ ├── colors.xml │ ├── dimens.xml │ ├── ic_launcher_background.xml │ ├── strings.xml │ └── styles.xml │ └── xml │ ├── backup.xml │ ├── backup_descriptor.xml │ ├── badge.xml │ ├── calendar.xml │ ├── drawer.xml │ └── prefs.xml ├── build.gradle.kts ├── gradle.properties ├── gradlew ├── gradlew.bat └── settings.gradle.kts /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle/ 2 | /gradle/ 3 | local.properties 4 | .idea/ 5 | !.idea/.name 6 | /build/ 7 | /app/build/ 8 | !/app/build/outputs/mapping 9 | *.iml 10 | *.apk 11 | *.db 12 | app/libs/ 13 | app/src/androidTest/ 14 | app/src/main/res/values-v14/ 15 | projectFilesBackup/ 16 | /app/src/main/play/ 17 | /app/release/ 18 | /captures/ 19 | -------------------------------------------------------------------------------- /Play Store/Play_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/F43nd1r/Multitool/7a8ac208154e9ea881e01baeba26d0efcbde1cc3/Play Store/Play_icon.png -------------------------------------------------------------------------------- /Play Store/Screenshot3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/F43nd1r/Multitool/7a8ac208154e9ea881e01baeba26d0efcbde1cc3/Play Store/Screenshot3.jpg -------------------------------------------------------------------------------- /Play Store/Screenshot4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/F43nd1r/Multitool/7a8ac208154e9ea881e01baeba26d0efcbde1cc3/Play Store/Screenshot4.jpg -------------------------------------------------------------------------------- /Play Store/Screenshot_2015-07-05-23-48-23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/F43nd1r/Multitool/7a8ac208154e9ea881e01baeba26d0efcbde1cc3/Play Store/Screenshot_2015-07-05-23-48-23.png -------------------------------------------------------------------------------- /Play Store/Screenshot_2015-07-05-23-48-35.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/F43nd1r/Multitool/7a8ac208154e9ea881e01baeba26d0efcbde1cc3/Play Store/Screenshot_2015-07-05-23-48-35.png -------------------------------------------------------------------------------- /Play Store/Screenshot_20160321-072345.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/F43nd1r/Multitool/7a8ac208154e9ea881e01baeba26d0efcbde1cc3/Play Store/Screenshot_20160321-072345.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Download - 2 | -------------------------------------------------------------------------------- /app/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("com.android.application") 3 | id("com.github.triplet.play") 4 | id("com.faendir.gradlekeepass") version "0.1" 5 | id("idea") 6 | } 7 | apply(plugin = "org.jetbrains.kotlin.android") 8 | apply(plugin = "org.jetbrains.kotlin.android.extensions") 9 | val versionCode: String by project 10 | var vCode = versionCode 11 | val version: String by project 12 | val androidKeyStoreFile: String by project 13 | val playKeyFile: String by project 14 | 15 | android { 16 | compileSdkVersion(28) 17 | 18 | defaultConfig { 19 | applicationId = "com.faendir.lightning_launcher.multitool" 20 | minSdkVersion(22) 21 | targetSdkVersion(28) 22 | versionCode = Integer.parseInt(vCode) 23 | versionName = version 24 | } 25 | signingConfigs { 26 | create("release") { 27 | storeFile = file(androidKeyStoreFile) 28 | val login = keepass.getLogin("intellij.android.key") 29 | storePassword = login.Password 30 | keyAlias = login.Login 31 | keyPassword = login.Password 32 | } 33 | } 34 | buildTypes { 35 | getByName("release") { 36 | isMinifyEnabled = true 37 | signingConfig = signingConfigs.getByName("release") 38 | proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro") 39 | } 40 | getByName("debug") { 41 | isMinifyEnabled = false 42 | proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro") 43 | } 44 | } 45 | lintOptions { 46 | isAbortOnError = false 47 | setLintConfig(file("lint.xml")) 48 | } 49 | compileOptions { 50 | setSourceCompatibility(JavaVersion.VERSION_1_8) 51 | setTargetCompatibility(JavaVersion.VERSION_1_8) 52 | } 53 | } 54 | 55 | play { 56 | serviceAccountCredentials = file(playKeyFile) 57 | track = if (version.contains("b")) "beta" else "production" 58 | } 59 | 60 | dependencies { 61 | implementation("com.faendir.lightninglauncher:scriptlib:4.1.1") 62 | implementation("androidx.appcompat:appcompat:1.1.0") 63 | implementation("androidx.recyclerview:recyclerview:1.1.0") 64 | implementation("androidx.preference:preference:1.1.0") 65 | implementation("com.google.android.material:material:1.0.0") 66 | implementation("com.google.code.gson:gson:2.8.5") 67 | implementation("ch.acra:acra-http:5.4.0") 68 | implementation("ch.acra:acra-limiter:5.4.0") 69 | implementation("ch.acra:acra-advanced-scheduler:5.4.0") 70 | implementation("org.greenrobot:eventbus:3.1.1") 71 | implementation("com.anjlab.android.iab.v3:library:1.0.44") 72 | implementation("com.mikepenz:materialdrawer:6.0.9") 73 | implementation("com.mikepenz:fastadapter-extensions:3.2.8") 74 | implementation("net.sourceforge.streamsupport:android-retrostreams:1.6.3") 75 | implementation("org.mozilla:rhino:1.7.10") 76 | implementation("com.evernote:android-job:1.2.6") 77 | compileOnly("com.google.auto.service:auto-service-annotations:1.0-rc6") 78 | annotationProcessor("com.google.auto.service:auto-service:1.0-rc6") 79 | implementation("androidx.constraintlayout:constraintlayout:1.1.3") 80 | implementation("org.apache.commons:commons-lang3:3.8.1") 81 | implementation("com.google.guava:guava:27.1-android") 82 | } 83 | 84 | tasks.register("increaseVersionNumber") { 85 | doLast { 86 | vCode = (Integer.parseInt(vCode) + 1).toString() 87 | android.defaultConfig.versionCode = Integer.parseInt(vCode) 88 | ant.withGroovyBuilder { 89 | "propertyfile"("file" to "../gradle.properties") { 90 | "entry"("key" to "versionCode", "value" to vCode) 91 | } 92 | } 93 | } 94 | } 95 | 96 | 97 | afterEvaluate { 98 | rootProject.tasks.getByName("confirmReleaseVersion").dependsOn(tasks.getByName("increaseVersionNumber")) 99 | rootProject.tasks.getByName("beforeReleaseBuild").dependsOn(tasks.getByName("clean")) 100 | rootProject.tasks.getByName("build").dependsOn(tasks.getByName("build")) 101 | rootProject.tasks.getByName("afterReleaseBuild").dependsOn(tasks.getByName("publishApkRelease")) 102 | } -------------------------------------------------------------------------------- /app/lint.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /home/pierrot/Devel/Android/SDKs/android-studio/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -keepattributes Signature, LineNumberTable, SourceFile, *Annotation*, EnclosingMethod 19 | 20 | -keep class * extends com.faendir.lightning_launcher.multitool.proxy.Proxy {*;} 21 | -keep class * extends com.faendir.lightning_launcher.multitool.proxy.JavaScript {*;} 22 | -keep class com.evernote.android.job.JobRequest$NetworkType {*;} 23 | 24 | -keep class * extends androidx.fragment.app.Fragment 25 | -keep class * extends android.app.Service {*;} 26 | -keep class androidx.preference.** 27 | 28 | -keep class sun.misc.Unsafe { *; } 29 | -keep class android.support.design.widget.** { *; } 30 | -keep interface android.support.design.widget.** { *; } 31 | -keepclassmembers class ** { 32 | @org.greenrobot.eventbus.Subscribe ; 33 | } 34 | -keep enum org.greenrobot.eventbus.ThreadMode { *; } 35 | 36 | -keep class kotlin.jvm.functions.** {*;} 37 | 38 | -dontwarn java.lang.invoke.* 39 | -dontwarn sun.misc.Unsafe 40 | -dontwarn org.mozilla.javascript.** 41 | -dontwarn build.* 42 | -dontwarn java.lang.ClassValue 43 | -dontwarn javax.lang.model.element.Modifier 44 | -------------------------------------------------------------------------------- /app/src/main/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/F43nd1r/Multitool/7a8ac208154e9ea881e01baeba26d0efcbde1cc3/app/src/main/ic_launcher-web.png -------------------------------------------------------------------------------- /app/src/main/ic_multitool-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/F43nd1r/Multitool/7a8ac208154e9ea881e01baeba26d0efcbde1cc3/app/src/main/ic_multitool-web.png -------------------------------------------------------------------------------- /app/src/main/ic_next-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/F43nd1r/Multitool/7a8ac208154e9ea881e01baeba26d0efcbde1cc3/app/src/main/ic_next-web.png -------------------------------------------------------------------------------- /app/src/main/ic_play-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/F43nd1r/Multitool/7a8ac208154e9ea881e01baeba26d0efcbde1cc3/app/src/main/ic_play-web.png -------------------------------------------------------------------------------- /app/src/main/ic_previous-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/F43nd1r/Multitool/7a8ac208154e9ea881e01baeba26d0efcbde1cc3/app/src/main/ic_previous-web.png -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/MultiTool.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool 2 | 3 | import android.app.Application 4 | import android.app.job.JobInfo.NETWORK_TYPE_UNMETERED 5 | import android.content.Context 6 | import com.evernote.android.job.JobManager 7 | import com.faendir.lightning_launcher.scriptlib.LightningServiceManager 8 | import com.google.common.util.concurrent.FutureCallback 9 | import net.pierrox.lightning_launcher.plugin.IScriptService 10 | import org.acra.ACRA 11 | import org.acra.annotation.AcraCore 12 | import org.acra.annotation.AcraHttpSender 13 | import org.acra.annotation.AcraLimiter 14 | import org.acra.annotation.AcraScheduler 15 | import org.acra.data.StringFormat 16 | import org.acra.sender.HttpSender 17 | import java.util.concurrent.atomic.AtomicInteger 18 | 19 | /** 20 | * Created by Lukas on 13.12.2015. 21 | * Main Application class 22 | */ 23 | @AcraCore(buildConfigClass = BuildConfig::class, reportFormat = StringFormat.JSON) 24 | @AcraHttpSender(uri = "https://acra.faendir.com/report", httpMethod = HttpSender.Method.POST, basicAuthLogin = "tM7oBAo83wcAmaCK", basicAuthPassword = "56Rb0aGfj697yTMG") 25 | @AcraScheduler(requiresNetworkType = NETWORK_TYPE_UNMETERED, requiresBatteryNotLow = true) 26 | @AcraLimiter 27 | class MultiTool : Application() { 28 | 29 | private lateinit var serviceManager: LightningServiceManager 30 | private val serviceUsers = AtomicInteger() 31 | 32 | init { 33 | instance = this 34 | } 35 | 36 | override fun attachBaseContext(base: Context) { 37 | super.attachBaseContext(base) 38 | if (DEBUG) { 39 | ACRA.DEV_LOGGING = true 40 | } 41 | ACRA.init(this) 42 | } 43 | 44 | override fun onCreate() { 45 | super.onCreate() 46 | JobManager.create(this) 47 | serviceManager = LightningServiceManager(this) 48 | } 49 | 50 | fun doInLL(function: (IScriptService) -> Unit) { 51 | serviceUsers.getAndIncrement() 52 | serviceManager.scriptService.addCallback(object : FutureCallback { 53 | override fun onSuccess(result: IScriptService?) { 54 | if (result != null) { 55 | function.invoke(result) 56 | } 57 | if (serviceUsers.decrementAndGet() == 0) { 58 | serviceManager.closeConnection() 59 | } 60 | } 61 | 62 | override fun onFailure(t: Throwable) { 63 | t.printStackTrace() 64 | if (serviceUsers.decrementAndGet() == 0) { 65 | serviceManager.closeConnection() 66 | } 67 | } 68 | }) { it.run() } 69 | } 70 | 71 | companion object { 72 | val DEBUG = BuildConfig.DEBUG 73 | const val LOG_TAG = "[MULTITOOL]" 74 | private lateinit var instance: MultiTool 75 | 76 | fun get(): MultiTool { 77 | return instance 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/animation/AnimationDemo.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.animation 2 | 3 | import android.content.Context 4 | import android.graphics.Color 5 | import android.graphics.PointF 6 | import android.util.AttributeSet 7 | import android.widget.HorizontalScrollView 8 | import android.widget.ImageView 9 | import android.widget.LinearLayout 10 | import androidx.appcompat.widget.AppCompatImageView 11 | import androidx.core.content.ContextCompat 12 | import androidx.core.graphics.drawable.DrawableCompat 13 | import com.faendir.lightning_launcher.multitool.R 14 | 15 | /** 16 | * @author lukas 17 | * @since 19.07.18 18 | */ 19 | class AnimationDemo(context: Context, attrs: AttributeSet) : HorizontalScrollView(context, attrs) { 20 | private val view1: ImageView 21 | private val view2: ImageView 22 | private val center: PointF 23 | private lateinit var size: Size 24 | private val percent: PointF 25 | private var animation: Animation? = null 26 | 27 | init { 28 | val layout = LinearLayout(context) 29 | layout.layoutParams = LayoutParams(0, 0) 30 | layout.orientation = LinearLayout.HORIZONTAL 31 | view1 = AppCompatImageView(context) 32 | view1.setLayoutParams(LinearLayout.LayoutParams(0, 0)) 33 | view1.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.animation_demo)) 34 | view1.setBackgroundColor(Color.WHITE) 35 | DrawableCompat.setTint(view1.getDrawable(), ContextCompat.getColor(context, R.color.accent)) 36 | view2 = AppCompatImageView(context) 37 | view2.setLayoutParams(LinearLayout.LayoutParams(0, 0)) 38 | view2.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.animation_demo_flipped)) 39 | view2.setBackgroundColor(Color.BLACK) 40 | DrawableCompat.setTint(view2.getDrawable(), ContextCompat.getColor(context, R.color.accent)) 41 | layout.addView(view1) 42 | layout.addView(view2) 43 | center = PointF(0f, 0f) 44 | percent = PointF(0f, 0f) 45 | addView(layout) 46 | post { 47 | size = Size(width, height) 48 | layout.layoutParams.width = size.width * 2 49 | layout.layoutParams.height = size.height 50 | view1.getLayoutParams().width = size.width 51 | view1.getLayoutParams().height = size.height 52 | view2.getLayoutParams().width = size.width 53 | view2.getLayoutParams().height = size.height 54 | center.x = (size.width / 2).toFloat() 55 | center.y = (size.height / 2).toFloat() 56 | requestLayout() 57 | } 58 | } 59 | 60 | override fun onScrollChanged(l: Int, t: Int, oldl: Int, oldt: Int) { 61 | super.onScrollChanged(l, t, oldl, oldt) 62 | if (animation != null) { 63 | percent.x = l.toFloat() / measuredWidth 64 | if (percent.x < 0) percent.x = 0f 65 | if (percent.x > 1) percent.x = 1f 66 | animation!!.getTransformation(percent, size, center, LEFT_PAGE).transform(view1, TRANSFORM_ALL, center) 67 | animation!!.getTransformation(percent, size, center, RIGHT_PAGE).transform(view2, TRANSFORM_ALL, center) 68 | } 69 | } 70 | 71 | fun setAnimation(animation: Animation) { 72 | this.animation = animation 73 | } 74 | 75 | companion object { 76 | private val LEFT_PAGE = PointB(x = true, y = true) 77 | private val RIGHT_PAGE = PointB(x = false, y = true) 78 | private val TRANSFORM_ALL = PointB(x = true, y = true) 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/animation/AnimationFragment.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.animation 2 | 3 | import android.animation.Animator 4 | import android.animation.AnimatorListenerAdapter 5 | import android.animation.ValueAnimator 6 | import android.app.AlertDialog 7 | import android.os.Bundle 8 | import android.view.* 9 | import android.view.animation.AccelerateDecelerateInterpolator 10 | import android.widget.CheckBox 11 | import android.widget.RadioButton 12 | import android.widget.RadioGroup 13 | import androidx.fragment.app.Fragment 14 | import com.faendir.lightning_launcher.multitool.R 15 | 16 | /** 17 | * @author lukas 18 | * @since 18.07.18 19 | */ 20 | class AnimationFragment : Fragment() { 21 | private var isReverse = false 22 | 23 | override fun onCreate(savedInstanceState: Bundle?) { 24 | super.onCreate(savedInstanceState) 25 | setHasOptionsMenu(true) 26 | } 27 | 28 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { 29 | val view = inflater.inflate(R.layout.fragment_animation, container, false) 30 | val radioAnimations = view.findViewById(R.id.radioAnimations) 31 | for (animation in Animation.values()) { 32 | val radioButton = RadioButton(activity) 33 | radioButton.setText(animation.label) 34 | radioButton.id = animation.ordinal 35 | radioAnimations.addView(radioButton) 36 | } 37 | val demo = view.findViewById(R.id.animationDemo) 38 | radioAnimations.setOnCheckedChangeListener { _, checkedId -> demo.setAnimation(Animation.values()[checkedId]) } 39 | radioAnimations.check(0) 40 | val shouldAnimate = view.findViewById(R.id.shouldAnimate) 41 | val animator = ValueAnimator.ofFloat(0F, 1F) 42 | animator.duration = 2000 43 | animator.interpolator = AccelerateDecelerateInterpolator() 44 | animator.addUpdateListener { animation -> demo.scrollTo(((if (isReverse) 1 - animation.animatedValue as Float else animation.animatedValue as Float) * demo.width).toInt(), 0) } 45 | animator.addListener(object : AnimatorListenerAdapter() { 46 | override fun onAnimationEnd(animation: Animator) { 47 | animator.startDelay = 1000 48 | isReverse = !isReverse 49 | animator.start() 50 | } 51 | }) 52 | animator.start() 53 | shouldAnimate.setOnCheckedChangeListener { _, isChecked -> 54 | if (!isChecked && animator.isRunning) { 55 | animator.pause() 56 | } else if (animator.isPaused) { 57 | animator.resume() 58 | } 59 | } 60 | return view 61 | } 62 | 63 | override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { 64 | inflater.inflate(R.menu.animation, menu) 65 | } 66 | 67 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 68 | if (item.itemId == R.id.action_help) { 69 | AlertDialog.Builder(activity).setTitle(R.string.title_help).setMessage(R.string.message_animationHelp).setPositiveButton(R.string.button_ok, null).show() 70 | } 71 | return true 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/animation/PointB.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.animation 2 | 3 | /** 4 | * @author lukas 5 | * @since 10.07.18 6 | */ 7 | class PointB(val x: Boolean, val y: Boolean) { 8 | 9 | fun any(): Boolean = x || y 10 | 11 | fun both(): Boolean = x && y 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/animation/Size.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.animation 2 | 3 | /** 4 | * @author lukas 5 | * @since 10.07.18 6 | */ 7 | class Size(val width: Int, val height: Int) 8 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/animation/Transformation.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.animation 2 | 3 | import android.graphics.PointF 4 | import android.view.View 5 | import com.faendir.lightning_launcher.multitool.proxy.Item 6 | import com.faendir.lightning_launcher.multitool.proxy.PropertySet 7 | 8 | /** 9 | * @author lukas 10 | * @since 10.07.18 11 | */ 12 | class Transformation { 13 | var scale = PointF(1f, 1f) 14 | var translate = PointF(0f, 0f) 15 | var pivot = PointF(0f, 0f) 16 | var turn = 0f 17 | var rotation = PointF(0f, 0f) 18 | var alpha = 1f 19 | private var partial = true 20 | 21 | fun transform(item: Item) { 22 | val pinMode = item.properties.getString(PropertySet.ITEM_PIN_MODE) 23 | val transform = PointB(!pinMode.contains("X"), !pinMode.contains("Y")) 24 | if (if (partial) transform.any() else transform.both()) { 25 | val center = AnimationScript.center(item, false) 26 | transform(item.rootView, transform, center) 27 | } 28 | } 29 | 30 | fun transform(view: View, transform: PointB, center: PointF) { 31 | view.pivotX = center.x + pivot.x 32 | view.pivotY = center.y + pivot.y 33 | val animator = view.animate().setDuration(0).alpha(alpha).rotation(turn * 360) 34 | if (transform.x) animator.scaleX(scale.x).translationX(translate.x).rotationX(rotation.x * 360) 35 | if (transform.y) animator.scaleY(scale.y).translationY(translate.y).rotationY(rotation.y * 360) 36 | animator.start() 37 | } 38 | 39 | fun onlyUnpinnedItems(): Transformation { 40 | partial = false 41 | return this 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/backup/BackupFragment.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.backup 2 | 3 | import android.app.AlertDialog 4 | import android.os.Bundle 5 | import android.view.Menu 6 | import android.view.MenuInflater 7 | import android.view.MenuItem 8 | import androidx.preference.PreferenceFragmentCompat 9 | import com.faendir.lightning_launcher.multitool.R 10 | import com.faendir.lightning_launcher.multitool.settings.PreferenceListener 11 | 12 | /** 13 | * @author lukas 14 | * @since 18.07.18 15 | */ 16 | class BackupFragment : PreferenceFragmentCompat() { 17 | private lateinit var listener: PreferenceListener 18 | 19 | override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { 20 | setHasOptionsMenu(true) 21 | setPreferencesFromResource(R.xml.backup, rootKey) 22 | listener = PreferenceListener(preferenceScreen) 23 | val backupChanged = { val activity = activity 24 | if(activity != null) BackupUtils.scheduleNext(activity) } 25 | listener.addPreference(getString(R.string.pref_backupTime), backupChanged) 26 | listener.addPreference(getString(R.string.pref_enableBackup), backupChanged) 27 | preferenceScreen.sharedPreferences.registerOnSharedPreferenceChangeListener(listener) 28 | } 29 | 30 | override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { 31 | inflater.inflate(R.menu.backup, menu) 32 | } 33 | 34 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 35 | if (item.itemId == R.id.action_help) { 36 | AlertDialog.Builder(activity).setTitle(R.string.title_help).setMessage(R.string.message_backupHelp).setPositiveButton(R.string.button_ok, null).show() 37 | } 38 | return true 39 | } 40 | 41 | override fun onDestroy() { 42 | preferenceScreen.sharedPreferences.unregisterOnSharedPreferenceChangeListener(listener) 43 | super.onDestroy() 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/backup/BackupJob.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.backup 2 | 3 | import androidx.annotation.Keep 4 | import com.evernote.android.job.Job 5 | import com.faendir.lightning_launcher.multitool.R 6 | import com.faendir.lightning_launcher.multitool.proxy.JavaScript 7 | import com.faendir.lightning_launcher.multitool.util.Utils 8 | import com.faendir.lightning_launcher.scriptlib.LightningServiceManager 9 | import net.pierrox.lightning_launcher.api.ScreenIdentity 10 | 11 | import java.util.concurrent.ExecutionException 12 | 13 | /** 14 | * @author F43nd1r 15 | * @since 30.01.2018 16 | */ 17 | @Keep 18 | class BackupJob : Job() { 19 | override fun onRunJob(params: Params): Result { 20 | val lightningServiceManager = LightningServiceManager(context) 21 | try { 22 | lightningServiceManager.scriptService.get().runCode("var " + JavaScript.Direct.PARAM_CLASS + " = " + BackupCreator::class.java.name + "\n" + Utils.readRawResource(context, R.raw.direct), ScreenIdentity.BACKGROUND) 23 | } catch (e: ExecutionException) { 24 | e.printStackTrace() 25 | } catch (e: InterruptedException) { 26 | e.printStackTrace() 27 | } 28 | 29 | BackupUtils.scheduleNext(context) 30 | return Result.SUCCESS 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/backup/BackupTime.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.backup 2 | 3 | /** 4 | * Created on 23.07.2016. 5 | * 6 | * @author F43nd1r 7 | */ 8 | class BackupTime(val hour: Int, val minute: Int, val days: List) 9 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/backup/BackupTimePreference.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.backup 2 | 3 | import android.content.Context 4 | import android.content.res.TypedArray 5 | import android.text.format.DateFormat 6 | import android.util.AttributeSet 7 | import android.view.View 8 | import android.widget.Button 9 | import android.widget.TimePicker 10 | import androidx.preference.Preference 11 | import androidx.preference.PreferenceViewHolder 12 | import com.faendir.lightning_launcher.multitool.R 13 | import java.util.* 14 | 15 | /** 16 | * @author lukas 17 | * @since 18.07.18 18 | */ 19 | class BackupTimePreference(context: Context, attrs: AttributeSet) : Preference(context, attrs), View.OnClickListener { 20 | private var backupTime: BackupTime 21 | private lateinit var buttons: MutableMap 22 | private lateinit var picker: TimePicker 23 | private var userOriginated = true 24 | 25 | init { 26 | layoutResource = R.layout.preference_backup_time 27 | backupTime = BackupUtils.getBackupTime(null) 28 | } 29 | 30 | override fun onBindViewHolder(holder: PreferenceViewHolder) { 31 | super.onBindViewHolder(holder) 32 | buttons = HashMap() 33 | buttons[holder.findViewById(R.id.buttonMonday) as Button] = Calendar.MONDAY 34 | buttons[holder.findViewById(R.id.buttonTuesday) as Button] = Calendar.TUESDAY 35 | buttons[holder.findViewById(R.id.buttonWednesday) as Button] = Calendar.WEDNESDAY 36 | buttons[holder.findViewById(R.id.buttonThursday) as Button] = Calendar.THURSDAY 37 | buttons[holder.findViewById(R.id.buttonFriday) as Button] = Calendar.FRIDAY 38 | buttons[holder.findViewById(R.id.buttonSaturday) as Button] = Calendar.SATURDAY 39 | buttons[holder.findViewById(R.id.buttonSunday) as Button] = Calendar.SUNDAY 40 | buttons.keys.forEach { it.setOnClickListener(this) } 41 | picker = holder.findViewById(R.id.timePicker) as TimePicker 42 | picker.setIs24HourView(DateFormat.is24HourFormat(context)) 43 | picker.setOnTimeChangedListener { _, _, _ -> persist() } 44 | showValue() 45 | } 46 | 47 | private fun showValue() { 48 | userOriginated = false 49 | for ((key, value) in buttons) { 50 | key.isSelected = backupTime.days.contains(value) 51 | } 52 | picker.currentHour = backupTime.hour 53 | picker.currentMinute = backupTime.minute 54 | userOriginated = true 55 | } 56 | 57 | override fun setEnabled(enabled: Boolean) { 58 | super.setEnabled(enabled) 59 | showValue() 60 | } 61 | 62 | private fun persist() { 63 | if (userOriginated) { 64 | val days = buttons.entries.filter { it.key.isSelected }.map { it.value }.toList() 65 | backupTime = BackupTime(picker.currentHour, picker.currentMinute, days) 66 | val time = BackupUtils.toString(backupTime) 67 | if (callChangeListener(time)) { 68 | persistString(time) 69 | } 70 | } 71 | } 72 | 73 | override fun onGetDefaultValue(a: TypedArray, index: Int): Any? = a.getString(index) 74 | 75 | override fun onSetInitialValue(defaultValue: Any?) { 76 | backupTime = BackupUtils.getBackupTime(getPersistedString(null)) 77 | } 78 | 79 | override fun onClick(view: View) { 80 | view.isSelected = !view.isSelected 81 | persist() 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/backup/BackupUtils.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.backup 2 | 3 | import android.content.Context 4 | import android.preference.PreferenceManager 5 | import android.text.format.DateFormat 6 | import com.evernote.android.job.JobManager 7 | import com.evernote.android.job.JobRequest 8 | import com.faendir.lightning_launcher.multitool.MultiTool 9 | import com.faendir.lightning_launcher.multitool.R 10 | import com.faendir.lightning_launcher.multitool.util.Utils.GSON 11 | import com.google.gson.JsonSyntaxException 12 | import java.util.* 13 | 14 | /** 15 | * Created on 23.07.2016. 16 | * 17 | * @author F43nd1r 18 | */ 19 | 20 | object BackupUtils { 21 | private const val HOUR_IN_MS = 1000 * 60 * 60 22 | private val DEFAULT = BackupTime(0, 0, listOf(Calendar.SUNDAY)) 23 | 24 | fun getBackupTime(s: String?): BackupTime { 25 | if(s != null) { 26 | try { 27 | return GSON.fromJson(s, BackupTime::class.java) 28 | } catch (e : JsonSyntaxException){ 29 | } 30 | } 31 | return DEFAULT 32 | } 33 | 34 | fun toString(backupTime: BackupTime): String { 35 | return GSON.toJson(backupTime) 36 | } 37 | 38 | fun toHumanReadableString(context: Context, backupTime: BackupTime): String { 39 | val days = ArrayList(backupTime.days) 40 | days.sort() 41 | if (days.remove(Integer.valueOf(Calendar.SUNDAY))) days.add(Calendar.SUNDAY) 42 | val calendar = Calendar.getInstance() 43 | calendar.set(Calendar.HOUR_OF_DAY, backupTime.hour) 44 | calendar.set(Calendar.MINUTE, backupTime.minute) 45 | return days.joinToString(", ", "", " " + DateFormat.getTimeFormat(context).format(calendar.time)) { day: Int -> 46 | val c = Calendar.getInstance() 47 | c.set(Calendar.DAY_OF_WEEK, day) 48 | c.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.SHORT, Locale.US).substring(0, 2) 49 | } 50 | } 51 | 52 | fun scheduleNext(context: Context) { 53 | val sharedPref = PreferenceManager.getDefaultSharedPreferences(context) 54 | val enabled = sharedPref.getBoolean(context.getString(R.string.pref_enableBackup), false) 55 | val time = getBackupTime(sharedPref.getString(context.getString(R.string.pref_backupTime), null)) 56 | if (enabled && time.days.isNotEmpty()) { 57 | val calendar = Calendar.getInstance() 58 | calendar.set(Calendar.MINUTE, time.minute) 59 | calendar.set(Calendar.HOUR_OF_DAY, time.hour) 60 | if (!Calendar.getInstance().before(calendar)) { 61 | calendar.add(Calendar.DATE, 1) 62 | } 63 | while (!time.days.contains(calendar.get(Calendar.DAY_OF_WEEK))) { 64 | calendar.add(Calendar.DATE, 1) 65 | } 66 | val timeMs = calendar.timeInMillis - Calendar.getInstance().timeInMillis 67 | JobRequest.Builder(BackupJob::class.java.name) 68 | .setUpdateCurrent(true) 69 | .setExecutionWindow(timeMs, timeMs + if (MultiTool.DEBUG) 1000 else HOUR_IN_MS) 70 | .build() 71 | .schedule() 72 | } else { 73 | JobManager.instance().cancelAllForTag(BackupJob::class.java.name) 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/badge/AppChooser.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.badge 2 | 3 | import android.app.AlertDialog 4 | import android.os.Bundle 5 | import android.preference.PreferenceManager 6 | import android.view.Menu 7 | import android.view.MenuItem 8 | import com.faendir.lightning_launcher.multitool.R 9 | import com.faendir.lightning_launcher.multitool.util.BaseActivity 10 | import com.faendir.lightning_launcher.multitool.util.IntentChooserFragment 11 | import com.faendir.lightning_launcher.multitool.util.IntentInfo 12 | import com.faendir.lightning_launcher.multitool.util.notification.NotificationDistributorService 13 | import java9.util.Comparators 14 | 15 | /** 16 | * @author F43nd1r 17 | * @since 07.11.2017 18 | */ 19 | 20 | class AppChooser : BaseActivity(R.layout.content_app_chooser) { 21 | private var byRelevance: Boolean = false 22 | 23 | override fun onCreate(savedInstanceState: Bundle?) { 24 | super.onCreate(savedInstanceState) 25 | setTitle(R.string.title_appChooser) 26 | byRelevance = true 27 | sort() 28 | if (NotificationDistributorService.isDisabled(this)) { 29 | NotificationDistributorService.askForEnable(this) 30 | } 31 | } 32 | 33 | override fun onCreateOptionsMenu(menu: Menu): Boolean { 34 | menuInflater.inflate(R.menu.menu_badge_app_chooser, menu) 35 | return super.onCreateOptionsMenu(menu) 36 | } 37 | 38 | private fun sort() { 39 | val fragment = (supportFragmentManager.findFragmentById(R.id.chooserFragment) as IntentChooserFragment?)!! 40 | if (byRelevance) { 41 | val sharedPref = PreferenceManager.getDefaultSharedPreferences(this) 42 | val highPriority: MutableSet = sharedPref.getStringSet(getString(R.string.key_badgeIntentPackages), emptySet())!! 43 | val prefix = getString(R.string.unread_prefix) 44 | val midPriority = sharedPref.all.keys.filter { it.startsWith(prefix) }.map { it.substring(prefix.length) }.toSet() 45 | fragment.setComparator (Comparator { o1, o2 -> 46 | 47 | val pn1 = o1.intent.component?.packageName 48 | 49 | val pn2 = o2.intent.component?.packageName 50 | val p1 = if (highPriority.contains(pn1)) 2 else if (midPriority.contains(pn1)) 1 else 0 51 | val p2 = if (highPriority.contains(pn2)) 2 else if (midPriority.contains(pn2)) 1 else 0 52 | val compare = Integer.compare(p2, p1) 53 | if (compare != 0) compare else o1.compareTo(o2) 54 | }) 55 | } else { 56 | fragment.setComparator(Comparators.comparing { it.name }) 57 | } 58 | } 59 | 60 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 61 | if (item.itemId == R.id.action_change_sorting) { 62 | AlertDialog.Builder(this) 63 | .setTitle(R.string.action_change_sorting) 64 | .setSingleChoiceItems(R.array.sortings, if (byRelevance) 0 else 1) { dialog, which -> 65 | byRelevance = which == 0 66 | sort() 67 | dialog.dismiss() 68 | } 69 | .show() 70 | } 71 | return super.onOptionsItemSelected(item) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/badge/BadgeDataSource.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.badge 2 | 3 | import android.content.ContentValues 4 | import android.content.Context 5 | import android.database.Cursor 6 | import android.net.Uri 7 | 8 | import com.faendir.lightning_launcher.multitool.R 9 | import com.faendir.lightning_launcher.multitool.util.Utils 10 | import com.faendir.lightning_launcher.multitool.util.provider.DataProvider 11 | import com.faendir.lightning_launcher.multitool.util.provider.SharedPreferencesDataSource 12 | 13 | /** 14 | * @author F43nd1r 15 | * @since 06.11.2017 16 | */ 17 | class BadgeDataSource : SharedPreferencesDataSource() { 18 | 19 | override val path = "badge/*" 20 | 21 | override fun query(context: Context, uri: Uri, projection: Array?, selection: String?, selectionArgs: Array?, sortOrder: String?): Cursor? { 22 | return super.query(context, uri, projection, selection, arrayOf(context.getString(R.string.unread_prefix) + uri.lastPathSegment!!), sortOrder) 23 | } 24 | 25 | companion object { 26 | 27 | fun getBadgeCount(context: Context, packageName: String): Int { 28 | context.contentResolver.query(getContentUri(packageName), null, null, null, null)?.use { cursor -> 29 | if (cursor.moveToFirst()) { 30 | val i = Utils.GSON.fromJson(cursor.getString(1), Int::class.java) 31 | if (i != null) { 32 | return i 33 | } 34 | } 35 | } 36 | return 0 37 | } 38 | 39 | fun setBadgeCount(context: Context, packageName: String, count: Int) { 40 | val contentValues = ContentValues() 41 | contentValues.put(context.getString(R.string.unread_prefix) + packageName, count) 42 | context.contentResolver.update(getContentUri(packageName), contentValues, null, null) 43 | } 44 | 45 | fun getContentUri(packageName: String): Uri { 46 | val uri = DataProvider.getContentUri() 47 | 48 | return uri.buildUpon().path(uri.path!!.replace("*", packageName)).build() 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/badge/BadgeFragment.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.badge 2 | 3 | import android.app.AlertDialog 4 | import android.os.Bundle 5 | import android.view.Menu 6 | import android.view.MenuInflater 7 | import android.view.MenuItem 8 | import androidx.preference.PreferenceFragmentCompat 9 | import com.faendir.lightning_launcher.multitool.R 10 | 11 | /** 12 | * @author lukas 13 | * @since 19.07.18 14 | */ 15 | class BadgeFragment : PreferenceFragmentCompat() { 16 | override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { 17 | setHasOptionsMenu(true) 18 | setPreferencesFromResource(R.xml.badge, rootKey) 19 | } 20 | 21 | override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) = inflater.inflate(R.menu.badge, menu) 22 | 23 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 24 | if (item.itemId == R.id.action_help) { 25 | AlertDialog.Builder(activity) 26 | .setTitle(R.string.title_help) 27 | .setMessage(R.string.message_helpBadge) 28 | .setPositiveButton(R.string.button_ok, null) 29 | .show() 30 | } 31 | return true 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/badge/BadgeListener.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.badge 2 | 3 | import android.os.Handler 4 | import androidx.annotation.Keep 5 | import com.faendir.lightning_launcher.multitool.R 6 | import com.faendir.lightning_launcher.multitool.proxy.JavaScript 7 | import com.faendir.lightning_launcher.multitool.proxy.ProxyFactory 8 | import com.faendir.lightning_launcher.multitool.proxy.Shortcut 9 | import com.faendir.lightning_launcher.multitool.proxy.Utils 10 | import com.faendir.lightning_launcher.multitool.util.provider.BaseContentListener 11 | 12 | /** 13 | * @author F43nd1r 14 | * @since 06.11.2017 15 | */ 16 | @Keep 17 | class BadgeListener(private val utils: Utils) : BaseContentListener(Handler(), utils.lightningContext, BadgeDataSource.getContentUri(utils.event.item!!.getTag(BadgeSetup.TAG_PACKAGE)!!)), JavaScript.Listener { 18 | private val item: Shortcut = ProxyFactory.cast(utils.event.item!!, Shortcut::class.java) 19 | private val packageName: String = item.getTag(BadgeSetup.TAG_PACKAGE)!! 20 | 21 | override fun onChange(selfChange: Boolean) { 22 | val count = BadgeDataSource.getBadgeCount(context, packageName) 23 | val showZero = utils.sharedPref.getBoolean(utils.getString(R.string.pref_showZero), true) 24 | if (!showZero && count == 0) { 25 | item.setVisibility(false) 26 | } else { 27 | item.label = count.toString() 28 | item.setVisibility(true) 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/badge/BadgeNotificationListener.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.badge 2 | 3 | import android.content.Context 4 | import android.content.SharedPreferences 5 | import android.preference.PreferenceManager 6 | import android.service.notification.NotificationListenerService 7 | import android.service.notification.StatusBarNotification 8 | import com.faendir.lightning_launcher.multitool.R 9 | import com.faendir.lightning_launcher.multitool.util.notification.NotificationListener 10 | import java9.lang.Iterables 11 | 12 | /** 13 | * @author F43nd1r 14 | * @since 03.07.2016 15 | */ 16 | class BadgeNotificationListener : NotificationListener { 17 | private lateinit var sharedPref: SharedPreferences 18 | 19 | override fun onCreate(context: NotificationListenerService) { 20 | sharedPref = PreferenceManager.getDefaultSharedPreferences(context) 21 | } 22 | 23 | override fun onNotificationPosted(context: NotificationListenerService, sbn: StatusBarNotification) { 24 | val packageName = sbn.packageName 25 | if (supportsIntentBasedCount(context, packageName)) { 26 | return 27 | } 28 | var number = sbn.notification.number 29 | if (number == 0) { 30 | val array = try { 31 | context.activeNotifications 32 | } catch (ignored: RuntimeException) { 33 | null 34 | } 35 | 36 | if (array != null) { 37 | val notifications = array.filter { packageName == it.packageName }.toList() 38 | val groupSizes = notifications.groupBy { it.groupKey }.mapValues { it.value.size }.toMutableMap() 39 | Iterables.removeIf(groupSizes.entries) { it.value == 1 } 40 | number = notifications.count() - groupSizes.size 41 | } 42 | if (number == 0) { 43 | number = 1 44 | } 45 | } 46 | BadgeDataSource.setBadgeCount(context, packageName, number) 47 | } 48 | 49 | override fun onNotificationRemoved(context: NotificationListenerService, sbn: StatusBarNotification) { 50 | if (supportsIntentBasedCount(context, sbn.packageName)) { 51 | return 52 | } 53 | BadgeDataSource.setBadgeCount(context, sbn.packageName, 0) 54 | } 55 | 56 | private fun supportsIntentBasedCount(context: Context, packageName: String): Boolean { 57 | return sharedPref.getStringSet(context.getString(R.string.key_badgeIntentPackages), emptySet())!!.contains(packageName) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/badge/BadgeSetup.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.badge 2 | 3 | import android.app.Activity 4 | import android.content.Intent 5 | import androidx.annotation.Keep 6 | import com.faendir.lightning_launcher.multitool.proxy.* 7 | 8 | /** 9 | * @author lukas 10 | * @since 08.07.18 11 | */ 12 | @Keep 13 | class BadgeSetup(private val utils: Utils) : JavaScript.Setup, JavaScript.ActivityResult { 14 | 15 | override fun setup() { 16 | val create = utils.installActivityResultScript() 17 | val screen = ProxyFactory.cast(utils.activeScreen, ActivityScreen::class.java) 18 | val d = utils.container 19 | val intent = Intent(utils.multitoolContext, AppChooser::class.java) 20 | screen.startActivityForResult(intent, create, javaClass.name + "/" + d.id) 21 | } 22 | 23 | override fun onActivityResult(resultCode: Int, data: Intent, token: String) { 24 | if (resultCode == Activity.RESULT_OK) { 25 | val d = utils.activeScreen.getContainerById(Integer.parseInt(token)) 26 | val resume = utils.installRegisterScript() 27 | val pause = utils.installUnregisterScript() 28 | val item = d.addShortcut("0", Intent(), 0f, 0f) 29 | val intent = data.getParcelableExtra(Intent.EXTRA_INTENT) 30 | 31 | item.setTag(TAG_PACKAGE, intent.component?.packageName) 32 | item.properties 33 | .edit() 34 | .setBoolean(PropertySet.ITEM_ON_GRID, false) 35 | .setBoolean(PropertySet.SHORTCUT_ICON_VISIBILITY, false) 36 | .setBoolean(PropertySet.SHORTCUT_LABEL_VISIBILITY, true) 37 | .setBoolean(PropertySet.ITEM_ENABLED, false) 38 | .setEventHandler(PropertySet.ITEM_RESUMED, EventHandler.RUN_SCRIPT, resume.id.toString() + "/" + BadgeListener::class.java.name) 39 | .setEventHandler(PropertySet.ITEM_PAUSED, EventHandler.RUN_SCRIPT, pause.id.toString()) 40 | .commit() 41 | utils.centerOnTouch(item) 42 | } 43 | } 44 | 45 | companion object { 46 | internal const val TAG_PACKAGE = "package" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/calendar/CalendarDataSource.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.calendar 2 | 3 | import android.Manifest 4 | import android.content.Context 5 | import android.content.pm.PackageManager 6 | import android.database.Cursor 7 | import android.net.Uri 8 | import android.provider.CalendarContract 9 | import androidx.core.content.ContextCompat 10 | import com.faendir.lightning_launcher.multitool.util.provider.QueryDataSource 11 | 12 | /** 13 | * @author lukas 14 | * @since 10.08.18 15 | */ 16 | class CalendarDataSource : QueryDataSource { 17 | override fun query(context: Context, uri: Uri, projection: Array?, selection: String?, selectionArgs: Array?, sortOrder: String?): Cursor? { 18 | if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CALENDAR) == PackageManager.PERMISSION_GRANTED) { 19 | val pathSegments = uri.pathSegments 20 | return context.contentResolver.query(CalendarContract.Instances.CONTENT_URI.buildUpon() 21 | .appendPath(pathSegments[pathSegments.size - 2]) 22 | .appendPath(pathSegments[pathSegments.size - 1]) 23 | .build(), projection, selection, selectionArgs, sortOrder) 24 | } 25 | return null 26 | } 27 | 28 | override val path = "calendar/*/*" 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/calendar/CalendarFragment.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.calendar 2 | 3 | import android.Manifest 4 | import android.os.Bundle 5 | import androidx.preference.PreferenceFragmentCompat 6 | import com.faendir.lightning_launcher.multitool.R 7 | import com.faendir.lightning_launcher.multitool.settings.PreferenceListener 8 | import com.faendir.lightning_launcher.scriptlib.PermissionActivity 9 | import com.google.common.util.concurrent.FutureCallback 10 | 11 | /** 12 | * @author lukas 13 | * @since 10.08.18 14 | */ 15 | class CalendarFragment : PreferenceFragmentCompat() { 16 | private lateinit var listener: PreferenceListener 17 | 18 | override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { 19 | setPreferencesFromResource(R.xml.calendar, rootKey) 20 | listener = PreferenceListener(preferenceScreen) 21 | listener.addPreferenceForSummary(getString(R.string.pref_calendars)) 22 | listener.addPreferenceForSummary(getString(R.string.pref_dateFormat)) 23 | preferenceScreen.sharedPreferences.registerOnSharedPreferenceChangeListener(listener) 24 | PermissionActivity.checkForPermission(activity!!, Manifest.permission.READ_CALENDAR).addCallback(object : FutureCallback { 25 | override fun onSuccess(result: Boolean?) { 26 | if (result != null && result) { 27 | (preferenceScreen.findPreference(getString(R.string.pref_calendars)) as CalendarPreference).refresh() 28 | } 29 | } 30 | 31 | override fun onFailure(t: Throwable) { 32 | t.printStackTrace() 33 | } 34 | }) { it.run() } 35 | } 36 | 37 | override fun onDestroy() { 38 | preferenceScreen.sharedPreferences.unregisterOnSharedPreferenceChangeListener(listener) 39 | super.onDestroy() 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/calendar/CalendarPreference.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.calendar 2 | 3 | import android.Manifest 4 | import android.content.Context 5 | import android.content.pm.PackageManager 6 | import android.content.res.TypedArray 7 | import android.provider.CalendarContract.Calendars 8 | import android.text.TextUtils 9 | import android.util.AttributeSet 10 | import androidx.core.content.ContextCompat 11 | import androidx.preference.MultiSelectListPreference 12 | import com.faendir.lightning_launcher.multitool.settings.SummaryPreference 13 | import java.util.* 14 | 15 | /** 16 | * @author lukas 17 | * @since 10.08.18 18 | */ 19 | class CalendarPreference(context: Context, attrs: AttributeSet) : MultiSelectListPreference(context, attrs), SummaryPreference { 20 | 21 | private fun getSelectedEntries(): List { 22 | val entries = entries.map { it.toString() }.toList() 23 | val values = entryValues.map { it.toString() }.toList() 24 | return getValues().asSequence().map { values.indexOf(it) }.filter { it >= 0 }.map { entries[it] }.sorted().toList() 25 | } 26 | 27 | init { 28 | refresh() 29 | } 30 | 31 | override val summaryText: CharSequence 32 | get() = TextUtils.join(", ", getSelectedEntries()) 33 | 34 | override fun onGetDefaultValue(a: TypedArray, index: Int): Any { 35 | val calendars = HashSet() 36 | if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CALENDAR) == PackageManager.PERMISSION_GRANTED) { 37 | context.contentResolver.query(Calendars.CONTENT_URI, arrayOf(Calendars._ID), Calendars.VISIBLE + " = 1", null, Calendars._ID + " ASC")?.use { 38 | while (it.moveToNext()) { 39 | calendars.add(it.getString(0)) 40 | } 41 | } 42 | } 43 | return calendars 44 | } 45 | 46 | fun refresh() { 47 | val calendars = HashMap() 48 | if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CALENDAR) == PackageManager.PERMISSION_GRANTED) { 49 | context.contentResolver 50 | .query(Calendars.CONTENT_URI, arrayOf(Calendars._ID, Calendars.NAME), Calendars.VISIBLE + " = 1", null, Calendars._ID + " ASC")?.use { 51 | while (it.moveToNext()) { 52 | val name: String? = it.getString(1) 53 | if(name != null) { 54 | calendars[it.getString(0)] = name 55 | } 56 | } 57 | } 58 | } 59 | entryValues = calendars.keys.toTypedArray() 60 | entries = calendars.values.toTypedArray() 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/drawer/DrawerFragment.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.drawer 2 | 3 | import android.os.Bundle 4 | import androidx.preference.PreferenceFragmentCompat 5 | import com.faendir.lightning_launcher.multitool.R 6 | 7 | /** 8 | * @author F43nd1r 9 | * @since 01.11.2016 10 | */ 11 | 12 | class DrawerFragment : PreferenceFragmentCompat() { 13 | override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) = setPreferencesFromResource(R.xml.drawer, rootKey) 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/drawer/RestorePreference.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.drawer 2 | 3 | import android.content.ComponentName 4 | import android.content.Context 5 | import android.content.pm.PackageManager 6 | import android.util.AttributeSet 7 | import androidx.preference.MultiSelectListPreference 8 | 9 | /** 10 | * @author F43nd1r 11 | * @since 13.11.2016 12 | */ 13 | 14 | class RestorePreference(context: Context, attrs: AttributeSet) : MultiSelectListPreference(context, attrs) { 15 | private val pm: PackageManager = getContext().packageManager 16 | 17 | init { 18 | isPersistent = true 19 | entries = arrayOfNulls(0) 20 | entryValues = arrayOfNulls(0) 21 | } 22 | 23 | private fun getLabelForComponent(flatComponent: String): String = pm.getActivityInfo(ComponentName.unflattenFromString(flatComponent), 0)?.loadLabel(pm).toString() 24 | 25 | override fun callChangeListener(newValue: Any): Boolean { 26 | val values = values 27 | values.removeAll(newValue as Collection<*>) 28 | super.callChangeListener(values) 29 | setValues(values) 30 | return false 31 | } 32 | 33 | override fun onSetInitialValue(defaultValue: Any?) { 34 | val values: Set? = if (defaultValue is Collection<*>) getPersistedStringSet(defaultValue.map { it.toString() }.toMutableSet()) else emptySet() 35 | entryValues = values?.toTypedArray() 36 | entries = values?.map { this.getLabelForComponent(it) }?.toTypedArray() 37 | setValues(values) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/event/ClickEvent.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.event 2 | 3 | import androidx.annotation.IdRes 4 | 5 | /** 6 | * Created on 01.04.2016. 7 | * 8 | * @author F43nd1r 9 | */ 10 | class ClickEvent(@IdRes val id: Int) 11 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/event/SwitchFragmentRequest.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.event 2 | 3 | import androidx.annotation.StringRes 4 | import com.faendir.lightning_launcher.multitool.util.Fragments 5 | 6 | /** 7 | * Created on 01.04.2016. 8 | * 9 | * @author F43nd1r 10 | */ 11 | class SwitchFragmentRequest(val fragment: Fragments) { 12 | 13 | val id: Int 14 | @StringRes 15 | get() = fragment.res 16 | 17 | constructor(@StringRes id: Int) : this(Fragments.values().first { it.res == id }) 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/fastadapter/ClickAwareModel.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.fastadapter 2 | 3 | /** 4 | * @author lukas 5 | * @since 04.07.18 6 | */ 7 | interface ClickAwareModel : Model { 8 | fun onClick() 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/fastadapter/DeletableModel.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.fastadapter 2 | 3 | import android.content.Context 4 | 5 | /** 6 | * @author F43nd1r 7 | * @since 13.10.2017 8 | */ 9 | 10 | interface DeletableModel : Model { 11 | fun getUndoText(context: Context): String 12 | override var name : String 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/fastadapter/ItemFactory.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.fastadapter 2 | 3 | import android.app.ActivityManager 4 | import android.content.Context 5 | 6 | /** 7 | * @author F43nd1r 8 | * @since 26.12.2017 9 | */ 10 | 11 | class ItemFactory(private val size: Int) { 12 | fun wrap(item: T): ExpandableItem = ExpandableItem(item, size) 13 | 14 | companion object { 15 | fun forLauncherIconSize(context: Context): ItemFactory = ItemFactory((context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager).launcherLargeIconSize) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/fastadapter/Model.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.fastadapter 2 | 3 | import android.content.Context 4 | import android.graphics.drawable.Drawable 5 | import androidx.annotation.ColorInt 6 | 7 | /** 8 | * @author F43nd1r 9 | * @since 11.10.2017 10 | */ 11 | 12 | interface Model { 13 | val name: String 14 | @get:ColorInt 15 | val tintColor: Int 16 | 17 | fun getIcon(context: Context): Drawable 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/gesture/GestureLibraryDataSource.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.gesture 2 | 3 | import android.content.Context 4 | 5 | import com.faendir.lightning_launcher.multitool.util.provider.FileDataSource 6 | 7 | import java.io.File 8 | 9 | /** 10 | * @author F43nd1r 11 | * @since 06.11.2017 12 | */ 13 | 14 | class GestureLibraryDataSource : FileDataSource { 15 | 16 | override val path = "lib" 17 | 18 | override fun getFile(context: Context): File = File(context.filesDir, "gestureLibrary") 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/gesture/GestureMetaDataSource.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.gesture 2 | 3 | import android.content.Context 4 | 5 | import com.faendir.lightning_launcher.multitool.util.provider.FileDataSource 6 | 7 | import java.io.File 8 | 9 | /** 10 | * @author F43nd1r 11 | * @since 06.11.2017 12 | */ 13 | 14 | class GestureMetaDataSource : FileDataSource { 15 | 16 | override val path = "infos" 17 | 18 | override fun getFile(context: Context): File = File(context.filesDir, "gestures") 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/gesture/GestureScript.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.gesture 2 | 3 | import android.content.Intent 4 | import android.util.Log 5 | import android.view.View 6 | import android.widget.TextView 7 | import androidx.annotation.Keep 8 | import com.faendir.lightning_launcher.multitool.MainActivity 9 | import com.faendir.lightning_launcher.multitool.MultiTool 10 | import com.faendir.lightning_launcher.multitool.R 11 | import com.faendir.lightning_launcher.multitool.proxy.* 12 | import com.faendir.lightning_launcher.multitool.util.FragmentManager 13 | 14 | /** 15 | * @author lukas 16 | * @since 09.07.18 17 | */ 18 | @Keep 19 | class GestureScript(private val utils: Utils) : JavaScript.CreateMenu, JavaScript.Setup, JavaScript.CreateCustomView { 20 | 21 | override fun showMenu(menu: Menu, item: Item) { 22 | val mode = menu.mode 23 | if (mode == Menu.MODE_ITEM_NO_EM || mode == Menu.MODE_ITEM_EM) { 24 | menu.addMainItem(utils.getString(R.string.menu_editGestures), utils.asFunction { 25 | val intent = Intent(utils.multitoolContext, MainActivity::class.java) 26 | intent.putExtra(FragmentManager.EXTRA_MODE, R.string.title_gestureLauncher) 27 | utils.lightningContext.startActivity(intent) 28 | menu.close() 29 | }) 30 | } 31 | } 32 | 33 | override fun setup() { 34 | val screen = utils.activeScreen 35 | val view = utils.container.addCustomView(screen.lastTouchX, screen.lastTouchY) 36 | view.setHorizontalGrab(true) 37 | view.setVerticalGrab(true) 38 | val script = utils.installCreateViewScript() 39 | val menu = utils.installMenuScript() 40 | view.properties 41 | .edit() 42 | .setString(PropertySet.VIEW_ON_CREATE, script.id.toString() + "/" + javaClass.name) 43 | .setString(PropertySet.ITEM_SELECTION_EFFECT, PropertySet.ITEM_SELECTION_EFFECT_PLAIN) 44 | .setEventHandler(PropertySet.ITEM_MENU, EventHandler.RUN_SCRIPT, menu.id.toString() + "/" + javaClass.name) 45 | .also { it.getBox(PropertySet.ITEM_BOX).setColor(Box.CONTENT, Box.MODE_ALL, 0x42FfFfFf) } 46 | .commit() 47 | } 48 | 49 | override fun onCreate(item: CustomView): View { 50 | item.setHorizontalGrab(true) 51 | item.setVerticalGrab(true) 52 | 53 | return try { 54 | LightningGestureView(utils) 55 | } catch (e: Exception) { 56 | Log.w(MultiTool.LOG_TAG, "Failed to load gesture widget") 57 | val t = TextView(utils.lightningContext) 58 | t.text = utils.getString(R.string.text_gestureViewFailed) 59 | t 60 | } 61 | 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/gesture/IntentChooser.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.gesture 2 | 3 | import android.app.Activity 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import android.view.MenuItem 7 | import androidx.fragment.app.Fragment 8 | import androidx.fragment.app.FragmentPagerAdapter 9 | import androidx.viewpager.widget.ViewPager 10 | import com.faendir.lightning_launcher.multitool.R 11 | import com.faendir.lightning_launcher.multitool.util.BaseActivity 12 | import com.faendir.lightning_launcher.multitool.util.IntentChooserFragment 13 | import com.google.android.material.tabs.TabLayout 14 | 15 | class IntentChooser : BaseActivity(R.layout.content_intent_chooser) { 16 | 17 | override fun onCreate(savedInstanceState: Bundle?) { 18 | super.onCreate(savedInstanceState) 19 | 20 | supportActionBar!!.setDisplayHomeAsUpEnabled(true) 21 | val tabLayout = findViewById(R.id.tabLayout) 22 | val viewPager = findViewById(R.id.viewpager) 23 | viewPager.adapter = object : FragmentPagerAdapter(supportFragmentManager) { 24 | override fun getItem(position: Int): Fragment { 25 | val intent: Intent 26 | val indirect: Boolean 27 | if (position == 0) { 28 | intent = Intent(Intent.ACTION_MAIN) 29 | intent.addCategory(Intent.CATEGORY_LAUNCHER) 30 | indirect = false 31 | } else { 32 | intent = Intent(Intent.ACTION_CREATE_SHORTCUT) 33 | indirect = true 34 | } 35 | return IntentChooserFragment.newInstance(intent, indirect) 36 | } 37 | 38 | override fun getCount(): Int = 2 39 | 40 | override fun getPageTitle(position: Int): CharSequence? = getString(if (position == 0) R.string.title_apps else R.string.title_shortcuts) 41 | } 42 | tabLayout.setupWithViewPager(viewPager) 43 | } 44 | 45 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 46 | if (item.itemId == android.R.id.home) { 47 | setResult(Activity.RESULT_CANCELED) 48 | finish() 49 | return true 50 | } 51 | return super.onOptionsItemSelected(item) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/gesture/LightningGestureView.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.gesture 2 | 3 | import android.content.Context 4 | import android.content.Intent 5 | import android.content.pm.PackageManager 6 | import android.gesture.Gesture 7 | import android.gesture.GestureOverlayView 8 | import android.gesture.Prediction 9 | import android.util.Log 10 | import android.widget.Toast 11 | import androidx.annotation.Keep 12 | import androidx.core.content.ContextCompat 13 | import com.faendir.lightning_launcher.multitool.BuildConfig 14 | import com.faendir.lightning_launcher.multitool.MultiTool.Companion.DEBUG 15 | import com.faendir.lightning_launcher.multitool.MultiTool.Companion.LOG_TAG 16 | import com.faendir.lightning_launcher.multitool.R 17 | import com.faendir.lightning_launcher.multitool.proxy.Utils 18 | import java9.util.stream.StreamSupport 19 | import java.util.* 20 | 21 | /** 22 | * Created on 26.01.2016. 23 | * 24 | * @author F43nd1r 25 | */ 26 | @Keep 27 | class LightningGestureView private constructor(lightningContext: Context, packageContext: Context) : GestureOverlayView(lightningContext), GestureOverlayView.OnGesturePerformedListener { 28 | init { 29 | addOnGesturePerformedListener(this) 30 | val color = ContextCompat.getColor(packageContext, R.color.accent) 31 | gestureColor = color 32 | uncertainGestureColor = color 33 | isEventsInterceptionEnabled = true 34 | if (DEBUG) Log.d(LOG_TAG, "Created gesture view") 35 | } 36 | 37 | @Throws(PackageManager.NameNotFoundException::class) 38 | constructor(context: Context) : this(context, context.createPackageContext(BuildConfig.APPLICATION_ID, Context.CONTEXT_IGNORE_SECURITY)) 39 | 40 | constructor(utils: Utils) : this(utils.lightningContext, utils.multitoolContext) 41 | 42 | override fun onGesturePerformed(overlay: GestureOverlayView, gesture: Gesture) { 43 | if (DEBUG) Log.d(LOG_TAG, "Gesture performed") 44 | val gestureInfos = GestureUtils.readFromFile(context) 45 | if (DEBUG) Log.d(LOG_TAG, "GestureInfos loaded") 46 | var recognized = false 47 | if (gestureInfos.isNotEmpty()) { 48 | val library = SingleStoreGestureLibrary.getInstance(context) 49 | if (DEBUG) Log.d(LOG_TAG, "Gestures loaded") 50 | val list: List? = library.recognize(gesture) 51 | if (list != null && list.isNotEmpty()) { 52 | if (DEBUG) Log.d(LOG_TAG, "Gesture recognized") 53 | try { 54 | val uuid = UUID.fromString(list[0].name) 55 | if (DEBUG) Log.d(LOG_TAG, "Gesture UUID $uuid") 56 | val info = StreamSupport.stream(gestureInfos).filter { gestureInfo -> gestureInfo.hasUuid(uuid) }.findAny() 57 | if (info.isPresent) { 58 | recognized = true 59 | val intent = info.get().intent 60 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 61 | context.startActivity(intent) 62 | if (DEBUG) Log.d(LOG_TAG, "Gesture launched") 63 | } else if (DEBUG) Log.w(LOG_TAG, "Bad gesture UUID") 64 | } catch (e: Exception) { 65 | e.printStackTrace() 66 | Toast.makeText(context, "Something went wrong while recognizing a gesture", Toast.LENGTH_SHORT).show() 67 | } 68 | 69 | } 70 | } 71 | if (!recognized) { 72 | if (DEBUG) Log.d(LOG_TAG, "Gesture not recognized") 73 | Toast.makeText(context, "Gesture not recognized", Toast.LENGTH_SHORT).show() 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/gesture/SingleStoreGestureLibrary.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.gesture 2 | 3 | import android.content.Context 4 | import android.gesture.Gesture 5 | import android.gesture.GestureStore 6 | import android.gesture.Prediction 7 | import android.util.Log 8 | import com.faendir.lightning_launcher.multitool.MultiTool.Companion.DEBUG 9 | import com.faendir.lightning_launcher.multitool.MultiTool.Companion.LOG_TAG 10 | import com.faendir.lightning_launcher.multitool.util.provider.DataProvider 11 | import org.acra.ACRA 12 | import java.io.IOException 13 | import java.util.* 14 | 15 | /** 16 | * Created on 26.01.2016. 17 | * 18 | * @author F43nd1r 19 | */ 20 | internal class SingleStoreGestureLibrary private constructor(private val context: Context) { 21 | 22 | init { 23 | if (DEBUG) Log.d(LOG_TAG, "Created Gesture Library") 24 | } 25 | 26 | fun save() { 27 | save(context) 28 | } 29 | 30 | fun recognize(gesture: Gesture): ArrayList { 31 | return gestureStore.recognize(gesture) 32 | } 33 | 34 | fun addGesture(entryName: String, gesture: Gesture) { 35 | synchronized(SingleStoreGestureLibrary::class.java) { 36 | gestureStore.addGesture(entryName, gesture) 37 | } 38 | } 39 | 40 | fun removeGesture(entryName: String, gesture: Gesture) { 41 | synchronized(SingleStoreGestureLibrary::class.java) { 42 | gestureStore.removeGesture(entryName, gesture) 43 | } 44 | } 45 | 46 | fun removeEntry(entryName: String) { 47 | synchronized(SingleStoreGestureLibrary::class.java) { 48 | gestureStore.removeEntry(entryName) 49 | } 50 | } 51 | 52 | fun getGestures(entryName: String): ArrayList? { 53 | return gestureStore.getGestures(entryName) 54 | } 55 | 56 | companion object { 57 | 58 | private lateinit var gestureStore: GestureStore 59 | 60 | @Synchronized 61 | fun getInstance(context: Context): SingleStoreGestureLibrary { 62 | val library = SingleStoreGestureLibrary(context) 63 | if (!::gestureStore.isInitialized) { 64 | if (DEBUG) Log.d(LOG_TAG, "Creating Gesture Library") 65 | gestureStore = GestureStore() 66 | load(context) 67 | } 68 | return library 69 | } 70 | 71 | @Synchronized 72 | private fun save(context: Context) { 73 | if (!gestureStore.hasChanged()) return 74 | try { 75 | gestureStore.save(DataProvider.openFileForWrite(context), true) 76 | } catch (e: IOException) { 77 | if (DEBUG) Log.d(LOG_TAG, "Could not save the gesture library", e) 78 | ACRA.getErrorReporter().handleSilentException(e) 79 | } 80 | 81 | } 82 | 83 | private fun load(context: Context) { 84 | try { 85 | DataProvider.openFileForRead(context)?.use { 86 | if (it.available() > 0) { 87 | gestureStore.load(it, false) 88 | } 89 | } 90 | } catch (e: IOException) { 91 | if (DEBUG) Log.d(LOG_TAG, "Could not load the gesture library", e) 92 | ACRA.getErrorReporter().handleSilentException(e) 93 | } 94 | 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/immersive/ImmersiveScript.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.immersive 2 | 3 | import android.app.Activity 4 | import android.os.Handler 5 | import android.view.View 6 | import androidx.annotation.Keep 7 | import com.faendir.lightning_launcher.multitool.proxy.EventHandler 8 | import com.faendir.lightning_launcher.multitool.proxy.JavaScript 9 | import com.faendir.lightning_launcher.multitool.proxy.PropertySet 10 | import com.faendir.lightning_launcher.multitool.proxy.Utils 11 | 12 | /** 13 | * @author lukas 14 | * @since 09.07.18 15 | */ 16 | @Keep 17 | class ImmersiveScript(private val utils: Utils) : JavaScript.Normal, JavaScript.Setup { 18 | 19 | override fun setup() { 20 | val script = utils.installNormalScript() 21 | val desktop = utils.activeScreen.currentDesktop 22 | val properties = desktop.properties 23 | val eventHandler = properties.getEventHandler(PropertySet.RESUMED) 24 | if (eventHandler?.action == EventHandler.RUN_SCRIPT && eventHandler.data?.startsWith(script.id.toString()) == true) { 25 | properties.edit().setEventHandler(PropertySet.RESUMED, EventHandler.UNSET, null).commit() 26 | (utils.lightningContext as? Activity)?.window?.decorView?.systemUiVisibility = 0 27 | } else { 28 | properties.edit().setEventHandler(PropertySet.RESUMED, EventHandler.RUN_SCRIPT, script.id.toString() + "/" + javaClass.name).commit() 29 | script.run(utils.activeScreen, ImmersiveScript::class.java.name) 30 | } 31 | } 32 | 33 | override fun run() { 34 | Handler(utils.lightningContext.mainLooper).post { 35 | (utils.lightningContext as? Activity)?.window?.decorView?.systemUiVisibility = View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_FULLSCREEN 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/launcherscript/Action.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.launcherscript 2 | 3 | import android.content.Context 4 | import android.graphics.Color 5 | import android.graphics.drawable.ColorDrawable 6 | import android.graphics.drawable.Drawable 7 | import androidx.core.content.ContextCompat 8 | import com.faendir.lightning_launcher.multitool.fastadapter.ClickAwareModel 9 | 10 | /** 11 | * @author lukas 12 | * @since 04.07.18 13 | */ 14 | class Action(override val name: String, private val onClick: () -> Unit) : ClickAwareModel { 15 | override fun getIcon(context: Context): Drawable = ColorDrawable(ContextCompat.getColor(context, android.R.color.transparent)) 16 | 17 | override val tintColor = Color.WHITE 18 | 19 | override fun onClick() = onClick.invoke() 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/launcherscript/ActionGroup.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.launcherscript 2 | 3 | import android.content.Context 4 | import android.graphics.Color 5 | import android.graphics.drawable.Drawable 6 | import androidx.core.content.ContextCompat 7 | import com.faendir.lightning_launcher.multitool.R 8 | import com.faendir.lightning_launcher.multitool.fastadapter.Model 9 | 10 | /** 11 | * @author lukas 12 | * @since 04.07.18 13 | */ 14 | class ActionGroup(override val name: String) : Model { 15 | 16 | override fun getIcon(context: Context): Drawable = ContextCompat.getDrawable(context, R.drawable.ic_arrow_drop_down_white)!! 17 | 18 | override val tintColor= Color.BLACK 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/launcherscript/LauncherScriptFragment.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.launcherscript 2 | 3 | import android.content.SharedPreferences 4 | import android.os.Bundle 5 | import android.preference.PreferenceManager 6 | import android.view.LayoutInflater 7 | import android.view.View 8 | import android.view.ViewGroup 9 | import android.widget.Button 10 | import android.widget.TextView 11 | import androidx.fragment.app.Fragment 12 | import com.faendir.lightning_launcher.multitool.MultiTool 13 | import com.faendir.lightning_launcher.multitool.R 14 | import com.faendir.lightning_launcher.multitool.event.ClickEvent 15 | import com.faendir.lightning_launcher.multitool.util.Utils 16 | import net.pierrox.lightning_launcher.api.Script 17 | import org.greenrobot.eventbus.EventBus 18 | import org.greenrobot.eventbus.Subscribe 19 | 20 | 21 | class LauncherScriptFragment : Fragment() { 22 | 23 | private lateinit var nameTextView: TextView 24 | private lateinit var sharedPrefs: SharedPreferences 25 | private lateinit var importButton: Button 26 | 27 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 28 | val v = inflater.inflate(R.layout.fragment_launcher_script, container, false) 29 | nameTextView = v.findViewById(R.id.main_scriptName) 30 | importButton = v.findViewById(R.id.button_import) 31 | sharedPrefs = PreferenceManager.getDefaultSharedPreferences(activity) 32 | nameTextView.text = sharedPrefs.getString(getString(R.string.preference_scriptName), getString(R.string.script_name)) 33 | return v 34 | } 35 | 36 | override fun onPause() { 37 | super.onPause() 38 | saveName() 39 | } 40 | 41 | private fun saveName() { 42 | //save the name preference 43 | sharedPrefs.edit().putString(getString(R.string.preference_scriptName), nameTextView.text.toString()).apply() 44 | } 45 | 46 | 47 | @Subscribe 48 | fun onButtonClick(event: ClickEvent) { 49 | if (event.id == R.id.button_import) { 50 | saveName() 51 | importButton.text = getString(R.string.button_repositoryImporter_importing) 52 | MultiTool.get().doInLL { scriptService -> 53 | scriptService.updateScript(Script(Utils.readRawResource(activity!!, R.raw.multitool), nameTextView.text.toString(), activity!!.packageName, Script.FLAG_APP_MENU or Script.FLAG_ITEM_MENU)) 54 | if (isAdded) { 55 | activity?.runOnUiThread { importButton.text = getString(R.string.button_repositoryImporter_importOk) } 56 | } 57 | } 58 | } 59 | 60 | } 61 | 62 | override fun onStart() { 63 | super.onStart() 64 | EventBus.getDefault().register(this) 65 | } 66 | 67 | override fun onStop() { 68 | super.onStop() 69 | EventBus.getDefault().unregister(this) 70 | } 71 | 72 | 73 | } 74 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/music/MusicDataSource.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.music 2 | 3 | import android.content.ContentValues 4 | import android.content.Context 5 | import android.database.Cursor 6 | import android.graphics.Bitmap 7 | import android.graphics.BitmapFactory 8 | import android.net.Uri 9 | import com.faendir.lightning_launcher.multitool.util.Utils 10 | import com.faendir.lightning_launcher.multitool.util.provider.DataProvider 11 | import com.faendir.lightning_launcher.multitool.util.provider.FileDataSource 12 | import com.faendir.lightning_launcher.multitool.util.provider.SharedPreferencesDataSource 13 | import java.io.File 14 | 15 | /** 16 | * @author F43nd1r 17 | * @since 06.11.2017 18 | */ 19 | 20 | class MusicDataSource : SharedPreferencesDataSource(), FileDataSource { 21 | 22 | override val path = "music" 23 | 24 | override fun query(context: Context, uri: Uri, projection: Array?, selection: String?, selectionArgs: Array?, sortOrder: String?): Cursor? { 25 | return super.query(context, uri, projection, selection, KEYS, sortOrder) 26 | } 27 | 28 | override fun getFile(context: Context): File = File(context.filesDir, "albumart.png") 29 | 30 | companion object { 31 | private const val KEY_TITLE = "music_title" 32 | private const val KEY_ARTIST = "music_artist" 33 | private const val KEY_ALBUM = "music_album" 34 | private const val KEY_PACKAGE = "music_package" 35 | private val KEYS = arrayOf(KEY_TITLE, KEY_ARTIST, KEY_ALBUM, KEY_PACKAGE) 36 | 37 | fun updateInfo(context: Context, info: TitleInfo) { 38 | val contentValues = ContentValues() 39 | contentValues.put(KEY_TITLE, info.title) 40 | contentValues.put(KEY_ARTIST, info.artist) 41 | contentValues.put(KEY_ALBUM, info.album) 42 | contentValues.put(KEY_PACKAGE, info.packageName) 43 | if (info.albumArt != null) { 44 | try { 45 | DataProvider.openFileForWrite(context).use { outputStream -> info.albumArt.compress(Bitmap.CompressFormat.PNG, 100, outputStream) } 46 | } catch (e: Exception) { 47 | e.printStackTrace() 48 | } 49 | 50 | } 51 | context.contentResolver.update(DataProvider.getContentUri(), contentValues, null, null) 52 | } 53 | 54 | fun queryInfo(context: Context): TitleInfo { 55 | var title = "" 56 | var album = "" 57 | var artist = "" 58 | var packageName = "" 59 | context.contentResolver.query(DataProvider.getContentUri(), null, null, null, null) 60 | ?.use { cursor -> 61 | while (cursor.moveToNext()) { 62 | when (cursor.getString(0)) { 63 | KEY_TITLE -> title = Utils.GSON.fromJson(cursor.getString(1), String::class.java) 64 | KEY_ALBUM -> album = Utils.GSON.fromJson(cursor.getString(1), String::class.java) 65 | KEY_ARTIST -> artist = Utils.GSON.fromJson(cursor.getString(1), String::class.java) 66 | KEY_PACKAGE -> packageName = Utils.GSON.fromJson(cursor.getString(1), String::class.java) 67 | } 68 | } 69 | } 70 | var albumArt: Bitmap? = null 71 | try { 72 | DataProvider.openFileForRead(context).use { inputStream -> albumArt = BitmapFactory.decodeStream(inputStream) } 73 | } catch (e: Exception) { 74 | e.printStackTrace() 75 | } 76 | 77 | return TitleInfo(title, album, artist, packageName, albumArt) 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/music/TitleInfo.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.music 2 | 3 | import android.graphics.Bitmap 4 | 5 | /** 6 | * @author F43nd1r 7 | * @since 06.11.2017 8 | */ 9 | 10 | data class TitleInfo(val title: String, val album: String, val artist: String, val packageName: String, val albumArt: Bitmap?) 11 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/proxy/ActivityScreen.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.proxy 2 | 3 | import android.content.Intent 4 | 5 | /** 6 | * @author lukas 7 | * @since 08.07.18 8 | */ 9 | interface ActivityScreen : Screen { 10 | fun cropImage(image: ImageBitmap, full_size: Boolean): ImageBitmap 11 | 12 | fun hideActionBar() 13 | 14 | fun pickColor(title: String, color: Int, hasAlpha: Boolean): Int 15 | 16 | fun pickImage(maxPixels: Int): Image 17 | 18 | fun pickNumericValue(title: String, value: Float, valueType: String, min: Float, max: Float, interval: Float, unit: String): Float 19 | 20 | fun showActionBar(onCreateOptionsMenu: Function, onOptionsItemSelected: Function) 21 | 22 | fun startActivityForResult(intent: Intent, receiver: Script, token: String): Boolean 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/proxy/Box.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.proxy 2 | 3 | import androidx.annotation.ColorLong 4 | import androidx.annotation.StringDef 5 | 6 | /** 7 | * @author lukas 8 | * @since 05.07.18 9 | */ 10 | interface Box : Proxy { 11 | 12 | @get:HorizontalAlignment 13 | val alignmentH: String 14 | 15 | @get:VerticalAlignment 16 | val alignmentV: String 17 | 18 | val box: Any 19 | 20 | fun getColor(@Area area: String, @Mode mode: String): Int 21 | 22 | fun getSize(@Area area: String): Int 23 | 24 | fun setAlignment(@HorizontalAlignment h: String, @VerticalAlignment v: String) 25 | 26 | fun setColor(areas: String, modes: String, @ColorLong color: Long) 27 | 28 | fun setSize(areas: String, size: Int) 29 | 30 | @Retention(AnnotationRetention.SOURCE) 31 | @StringDef(MARGIN_LEFT, MARGIN_TOP, MARGIN_RIGHT, MARGIN_BOTTOM, BORDER_LEFT, BORDER_TOP, BORDER_RIGHT, BORDER_BOTTOM, PADDING_LEFT, PADDING_TOP, PADDING_RIGHT, PADDING_BOTTOM, CONTENT) 32 | annotation class Area 33 | 34 | @Retention(AnnotationRetention.SOURCE) 35 | @StringDef(MODE_NORMAL, MODE_FOCUSED, MODE_SELECTED) 36 | annotation class Mode 37 | 38 | @Retention(AnnotationRetention.SOURCE) 39 | @StringDef(ALIGNMENT_LEFT, ALIGNMENT_CENTER, ALIGNMENT_RIGHT) 40 | annotation class HorizontalAlignment 41 | 42 | @Retention(AnnotationRetention.SOURCE) 43 | @StringDef(ALIGNMENT_TOP, ALIGNMENT_MIDDLE, ALIGNMENT_BOTTOM) 44 | annotation class VerticalAlignment 45 | 46 | companion object { 47 | const val MARGIN_LEFT = "ml" 48 | const val MARGIN_TOP = "mt" 49 | const val MARGIN_RIGHT = "mr" 50 | const val MARGIN_BOTTOM = "mb" 51 | const val BORDER_LEFT = "bl" 52 | const val BORDER_TOP = "bt" 53 | const val BORDER_RIGHT = "br" 54 | const val BORDER_BOTTOM = "bb" 55 | const val PADDING_LEFT = "pl" 56 | const val PADDING_TOP = "pt" 57 | const val PADDING_RIGHT = "pr" 58 | const val PADDING_BOTTOM = "pb" 59 | const val CONTENT = "c" 60 | const val MODE_NORMAL = "n" 61 | const val MODE_FOCUSED = "f" 62 | const val MODE_SELECTED = "s" 63 | const val MODE_ALL = MODE_NORMAL + MODE_FOCUSED + MODE_SELECTED 64 | const val ALIGNMENT_LEFT = "LEFT" 65 | const val ALIGNMENT_CENTER = "CENTER" 66 | const val ALIGNMENT_RIGHT = "RIGHT" 67 | const val ALIGNMENT_TOP = "TOP" 68 | const val ALIGNMENT_MIDDLE = "MIDDLE" 69 | const val ALIGNMENT_BOTTOM = "BOTTOM" 70 | 71 | fun asString(@Area vararg areas: String): String = areas.joinToString(",") 72 | 73 | fun border(): String = asString(BORDER_LEFT, BORDER_TOP, BORDER_RIGHT, BORDER_BOTTOM) 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/proxy/Container.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.proxy 2 | 3 | import android.content.Intent 4 | import androidx.annotation.StringDef 5 | 6 | /** 7 | * @author lukas 8 | * @since 04.07.18 9 | */ 10 | interface Container : Proxy { 11 | 12 | @get:Type 13 | val type: String 14 | 15 | val id: Int 16 | 17 | val tag: String 18 | 19 | val opener: Item 20 | 21 | val width: Int 22 | 23 | val height: Int 24 | 25 | val boundingBox: RectL 26 | 27 | val cellWidth: Float 28 | 29 | val cellHeight: Float 30 | 31 | val positionX: Float 32 | 33 | val positionY: Float 34 | 35 | val positionScale: Float 36 | 37 | val allItems: Array 38 | 39 | val properties: PropertySet 40 | 41 | val my: Scriptable 42 | 43 | fun removeItem(item: Item) 44 | 45 | fun setTag(id: String, value: String?) 46 | 47 | fun getItemByName(name: String): Item 48 | 49 | fun addPanel(x: Float, y: Float, width: Float, height: Float): Panel 50 | 51 | fun addShortcut(label: String, intent: Intent, x: Float, y: Float): Shortcut 52 | 53 | fun addCustomView(x: Float, y: Float): CustomView 54 | 55 | fun getTag(id: String): String? 56 | 57 | @Retention(AnnotationRetention.SOURCE) 58 | @StringDef(TYPE_DESKTOP, TYPE_FOLDER) 59 | annotation class Type 60 | 61 | companion object { 62 | const val TYPE_DESKTOP = "Desktop" 63 | const val TYPE_FOLDER = "Folder" 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/proxy/CustomView.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.proxy 2 | 3 | /** 4 | * @author lukas 5 | * @since 09.07.18 6 | */ 7 | interface CustomView : Item { 8 | fun setHorizontalGrab(grab: Boolean) 9 | 10 | fun setVerticalGrab(grab: Boolean) 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/proxy/Desktop.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.proxy 2 | 3 | /** 4 | * @author lukas 5 | * @since 04.07.18 6 | */ 7 | interface Desktop : Container { 8 | val name: String 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/proxy/Event.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.proxy 2 | 3 | /** 4 | * @author lukas 5 | * @since 04.07.18 6 | */ 7 | interface Event : Proxy { 8 | val item: Item? 9 | 10 | val source: String 11 | 12 | val date: Long 13 | 14 | val container: Container 15 | 16 | val screen: Screen 17 | 18 | val data: String 19 | 20 | val touchX: Float 21 | 22 | val touchY: Float 23 | 24 | val touchScreenX: Float 25 | 26 | val touchScreenY: Float 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/proxy/EventHandler.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.proxy 2 | 3 | import android.content.Context 4 | 5 | /** 6 | * @author lukas 7 | * @since 05.07.18 8 | */ 9 | interface EventHandler : Proxy { 10 | 11 | val action: Int 12 | 13 | val data: String? 14 | 15 | fun setNext(next: EventHandler?) 16 | 17 | companion object { 18 | const val RUN_SCRIPT = 35 19 | const val RESTART = 28 20 | const val UNSET = 0 21 | 22 | fun newInstance(context: Context, action: Int, data: String): EventHandler { 23 | try { 24 | return ProxyFactory.lightningProxy(context.classLoader 25 | .loadClass("net.pierrox.lightning_launcher.script.api.EventHandler") 26 | .getConstructor(Int::class.javaPrimitiveType, String::class.java) 27 | .newInstance(action, data), EventHandler::class.java) 28 | } catch (e: Exception) { 29 | throw RuntimeException(e) 30 | } 31 | 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/proxy/Folder.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.proxy 2 | 3 | /** 4 | * @author lukas 5 | * @since 08.07.18 6 | */ 7 | interface Folder : Shortcut { 8 | val container: Container 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/proxy/Function.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.proxy 2 | 3 | /** 4 | * @author lukas 5 | * @since 17.07.18 6 | */ 7 | interface Function : Proxy 8 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/proxy/Image.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.proxy 2 | 3 | import android.content.Context 4 | import androidx.annotation.StringDef 5 | 6 | /** 7 | * @author lukas 8 | * @since 04.07.18 9 | */ 10 | interface Image : Proxy { 11 | val width: Int 12 | 13 | val height: Int 14 | 15 | @get:Type 16 | val type: String 17 | 18 | interface Class : Proxy { 19 | 20 | fun createImage(width: Int, height: Int): ImageBitmap 21 | 22 | fun createImage(pkg: String, name: String): Image 23 | 24 | companion object { 25 | operator fun get(context: Context): Class { 26 | try { 27 | return ProxyFactory.lightningProxy(context.classLoader.loadClass("net.pierrox.lightning_launcher.script.api.Image"), Class::class.java) 28 | } catch (e: ClassNotFoundException) { 29 | throw RuntimeException(e) 30 | } 31 | 32 | } 33 | } 34 | } 35 | 36 | @Retention(AnnotationRetention.SOURCE) 37 | @StringDef(TYPE_BITMAP) 38 | annotation class Type 39 | 40 | companion object { 41 | const val TYPE_BITMAP = "BITMAP" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/proxy/ImageBitmap.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.proxy 2 | 3 | import android.graphics.Bitmap 4 | import android.graphics.Canvas 5 | 6 | /** 7 | * @author lukas 8 | * @since 04.07.18 9 | */ 10 | interface ImageBitmap : Image { 11 | 12 | val bitmap: Bitmap 13 | 14 | fun draw(): Canvas 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/proxy/Item.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.proxy 2 | 3 | import android.view.View 4 | import androidx.annotation.StringDef 5 | 6 | /** 7 | * @author lukas 8 | * @since 04.07.18 9 | */ 10 | interface Item : Proxy { 11 | 12 | var name: String 13 | 14 | val id: Int 15 | 16 | val tag: String 17 | 18 | @get:Type 19 | val type: String 20 | 21 | val width: Int 22 | 23 | val height: Int 24 | 25 | val positionX: Float 26 | 27 | val positionY: Float 28 | 29 | val scaleX: Float 30 | 31 | val scaleY: Float 32 | 33 | var rotation: Float 34 | 35 | val cell: RectL 36 | 37 | val isVisible: Boolean 38 | 39 | val properties: PropertySet 40 | 41 | val parent: Container 42 | 43 | val rootView: View 44 | 45 | fun getTag(id: String): String? 46 | 47 | fun getBoxBackground(@Box.Mode state: String): Image 48 | 49 | fun setSize(width: Float, height: Float) 50 | 51 | fun setTag(id: String, value: String?) 52 | 53 | fun setCell(left: Int, top: Int, right: Int, bottom: Int) 54 | 55 | fun setCell(left: Int, top: Int, right: Int, bottom: Int, portrait: Boolean) 56 | 57 | fun setPosition(x: Float, y: Float) 58 | 59 | fun setScale(scaleX: Float, scaleY: Float) 60 | 61 | fun setSkew(skewX: Float, skewY: Float) 62 | 63 | fun setVisibility(visible: Boolean) 64 | 65 | fun setBoxBackground(image: Image, @Box.Mode state: String, persistent: Boolean) 66 | 67 | fun setBinding(@PropertySet.BindingProperty target: String, formula: String, enabled: Boolean) 68 | 69 | @Retention(AnnotationRetention.SOURCE) 70 | @StringDef(TYPE_SHORTCUT, TYPE_FOLDER, TYPE_PANEL) 71 | annotation class Type 72 | 73 | companion object { 74 | const val TYPE_SHORTCUT = "Shortcut" 75 | const val TYPE_FOLDER = "Folder" 76 | const val TYPE_PANEL = "Panel" 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/proxy/JavaScript.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.proxy 2 | 3 | import android.content.Intent 4 | import android.view.View 5 | import androidx.annotation.Keep 6 | 7 | /** 8 | * @author lukas 9 | * @since 09.07.18 10 | */ 11 | interface JavaScript { 12 | @Keep 13 | interface CreateMenu : JavaScript { 14 | fun showMenu(jsMenu: Any, jsItem: Any) { 15 | showMenu(ProxyFactory.lightningProxy(jsMenu, Menu::class.java), ProxyFactory.lightningProxy(jsItem, Item::class.java)) 16 | } 17 | 18 | fun showMenu(menu: Menu, item: Item) 19 | } 20 | 21 | @Keep 22 | interface ActivityResult : JavaScript { 23 | fun onActivityResult(resultCode: Int, data: Intent, token: String) 24 | } 25 | 26 | @Keep 27 | interface CreateCustomView : JavaScript { 28 | fun onCreate(jsItem: Any): View { 29 | return onCreate(ProxyFactory.lightningProxy(jsItem, CustomView::class.java)) 30 | } 31 | 32 | fun onCreate(item: CustomView): View 33 | } 34 | 35 | @Keep 36 | interface Setup : JavaScript { 37 | fun setup() 38 | } 39 | 40 | @Keep 41 | interface Normal : JavaScript { 42 | fun run() 43 | } 44 | 45 | @Keep 46 | interface Direct : JavaScript { 47 | 48 | fun execute(data: String): String 49 | 50 | companion object { 51 | const val PARAM_CLASS = "multitool\$classname" 52 | const val PARAM_DATA = "multitool\$data" 53 | } 54 | } 55 | 56 | @Keep 57 | interface Listener : JavaScript { 58 | fun register() 59 | 60 | fun unregister() 61 | 62 | fun handleCommand(command: String) {} 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /app/src/main/java/com/faendir/lightning_launcher/multitool/proxy/Lightning.kt: -------------------------------------------------------------------------------- 1 | package com.faendir.lightning_launcher.multitool.proxy 2 | 3 | /** 4 | * @author lukas 5 | * @since 05.07.18 6 | */ 7 | interface Lightning : Proxy { 8 | val event: Event 9 | 10 | val variables: VariableSet 11 | 12 | val activeScreen: Screen 13 | 14 | val currentScript: Script 15 | 16 | fun save() 17 | 18 | fun getScriptByPathAndName(path: String, name: String): Script? 19 | 20 | fun createScript(path: String, name: String, text: String, flags: Int): Script 21 | 22 | fun getScriptById(id: String): Script 23 | 24 | fun deleteScript(script: Script) 25 | 26 | fun getAllScriptMatching(flags: Int): Array