First poc
This commit is contained in:
parent
bfd5a134da
commit
37a8f3c2b7
@ -76,6 +76,18 @@
|
|||||||
<option name="screenX" value="1080" />
|
<option name="screenX" value="1080" />
|
||||||
<option name="screenY" value="2340" />
|
<option name="screenY" value="2340" />
|
||||||
</PersistentDeviceSelectionData>
|
</PersistentDeviceSelectionData>
|
||||||
|
<PersistentDeviceSelectionData>
|
||||||
|
<option name="api" value="34" />
|
||||||
|
<option name="brand" value="samsung" />
|
||||||
|
<option name="codename" value="a16x" />
|
||||||
|
<option name="id" value="a16x" />
|
||||||
|
<option name="labId" value="google" />
|
||||||
|
<option name="manufacturer" value="Samsung" />
|
||||||
|
<option name="name" value="A16 5G" />
|
||||||
|
<option name="screenDensity" value="450" />
|
||||||
|
<option name="screenX" value="1080" />
|
||||||
|
<option name="screenY" value="2340" />
|
||||||
|
</PersistentDeviceSelectionData>
|
||||||
<PersistentDeviceSelectionData>
|
<PersistentDeviceSelectionData>
|
||||||
<option name="api" value="34" />
|
<option name="api" value="34" />
|
||||||
<option name="brand" value="samsung" />
|
<option name="brand" value="samsung" />
|
||||||
|
@ -4,6 +4,14 @@
|
|||||||
<selectionStates>
|
<selectionStates>
|
||||||
<SelectionState runConfigName="app">
|
<SelectionState runConfigName="app">
|
||||||
<option name="selectionMode" value="DROPDOWN" />
|
<option name="selectionMode" value="DROPDOWN" />
|
||||||
|
<DropdownSelection timestamp="2025-05-02T20:56:34.144725876Z">
|
||||||
|
<Target type="DEFAULT_BOOT">
|
||||||
|
<handle>
|
||||||
|
<DeviceId pluginId="Default" identifier="serial=192.168.0.192:37353;connection=b4c14d05" />
|
||||||
|
</handle>
|
||||||
|
</Target>
|
||||||
|
</DropdownSelection>
|
||||||
|
<DialogSelection />
|
||||||
</SelectionState>
|
</SelectionState>
|
||||||
</selectionStates>
|
</selectionStates>
|
||||||
</component>
|
</component>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="VcsDirectoryMappings" defaultProject="true" />
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
</project>
|
</project>
|
@ -4,12 +4,47 @@
|
|||||||
<shared>
|
<shared>
|
||||||
<config />
|
<config />
|
||||||
</shared>
|
</shared>
|
||||||
|
<layouts>
|
||||||
|
<layout url="file://$PROJECT_DIR$/app/src/main/res/layout/activity_transparent.xml">
|
||||||
|
<config>
|
||||||
|
<theme>@style/Theme.Transparent</theme>
|
||||||
|
</config>
|
||||||
|
</layout>
|
||||||
|
</layouts>
|
||||||
</component>
|
</component>
|
||||||
<component name="AutoImportSettings">
|
<component name="AutoImportSettings">
|
||||||
<option name="autoReloadType" value="NONE" />
|
<option name="autoReloadType" value="NONE" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="85e0dc1a-d7e2-4ab4-a8ad-e708732e10e5" name="Changes" comment="" />
|
<list default="true" id="85e0dc1a-d7e2-4ab4-a8ad-e708732e10e5" name="Changes" comment="Improve .gitignore">
|
||||||
|
<change beforePath="$PROJECT_DIR$/.gitignore" beforeDir="false" afterPath="$PROJECT_DIR$/.gitignore" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/.gradle/8.11.1/checksums/checksums.lock" beforeDir="false" afterPath="$PROJECT_DIR$/.gradle/8.11.1/checksums/checksums.lock" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/.gradle/8.11.1/checksums/md5-checksums.bin" beforeDir="false" afterPath="$PROJECT_DIR$/.gradle/8.11.1/checksums/md5-checksums.bin" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/.gradle/8.11.1/checksums/sha1-checksums.bin" beforeDir="false" afterPath="$PROJECT_DIR$/.gradle/8.11.1/checksums/sha1-checksums.bin" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/.gradle/8.11.1/executionHistory/executionHistory.bin" beforeDir="false" afterPath="$PROJECT_DIR$/.gradle/8.11.1/executionHistory/executionHistory.bin" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/.gradle/8.11.1/executionHistory/executionHistory.lock" beforeDir="false" afterPath="$PROJECT_DIR$/.gradle/8.11.1/executionHistory/executionHistory.lock" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/.gradle/8.11.1/fileHashes/fileHashes.bin" beforeDir="false" afterPath="$PROJECT_DIR$/.gradle/8.11.1/fileHashes/fileHashes.bin" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/.gradle/8.11.1/fileHashes/fileHashes.lock" beforeDir="false" afterPath="$PROJECT_DIR$/.gradle/8.11.1/fileHashes/fileHashes.lock" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/.gradle/8.11.1/fileHashes/resourceHashesCache.bin" beforeDir="false" afterPath="$PROJECT_DIR$/.gradle/8.11.1/fileHashes/resourceHashesCache.bin" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/.gradle/buildOutputCleanup/buildOutputCleanup.lock" beforeDir="false" afterPath="$PROJECT_DIR$/.gradle/buildOutputCleanup/buildOutputCleanup.lock" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/.gradle/buildOutputCleanup/outputFiles.bin" beforeDir="false" afterPath="$PROJECT_DIR$/.gradle/buildOutputCleanup/outputFiles.bin" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/.gradle/config.properties" beforeDir="false" afterPath="$PROJECT_DIR$/.gradle/config.properties" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/.gradle/file-system.probe" beforeDir="false" afterPath="$PROJECT_DIR$/.gradle/file-system.probe" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/.idea/caches/deviceStreaming.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/caches/deviceStreaming.xml" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/.idea/deploymentTargetSelector.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/deploymentTargetSelector.xml" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/.idea/misc.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/misc.xml" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/.idea/vcs.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/vcs.xml" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/app/build.gradle.kts" beforeDir="false" afterPath="$PROJECT_DIR$/app/build.gradle.kts" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/app/src/main/AndroidManifest.xml" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/AndroidManifest.xml" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/app/src/main/java/de/polyfish0/pamauth/MainActivity.kt" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/java/de/polyfish0/pamauth/MainActivity.kt" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/app/src/main/java/de/polyfish0/pamauth/services/PAMServerService.kt" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/java/de/polyfish0/pamauth/services/PAMServerService.kt" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/app/src/main/res/values/colors.xml" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/res/values/colors.xml" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/app/src/main/res/values/themes.xml" beforeDir="false" afterPath="$PROJECT_DIR$/app/src/main/res/values/themes.xml" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/build/reports/problems/problems-report.html" beforeDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/gradle/libs.versions.toml" beforeDir="false" afterPath="$PROJECT_DIR$/gradle/libs.versions.toml" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/local.properties" beforeDir="false" afterPath="$PROJECT_DIR$/local.properties" afterDir="false" />
|
||||||
|
</list>
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||||
@ -18,7 +53,7 @@
|
|||||||
<component name="ClangdSettings">
|
<component name="ClangdSettings">
|
||||||
<option name="formatViaClangd" value="false" />
|
<option name="formatViaClangd" value="false" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ExecutionTargetManager" SELECTED_TARGET="device_and_snapshot_combo_box_target[]" />
|
<component name="ExecutionTargetManager" SELECTED_TARGET="device_and_snapshot_combo_box_target[DeviceId(pluginId=Default, isTemplate=false, identifier=serial=192.168.0.192:37353;connection=b4c14d05)]" />
|
||||||
<component name="ExternalProjectsData">
|
<component name="ExternalProjectsData">
|
||||||
<projectState path="$PROJECT_DIR$">
|
<projectState path="$PROJECT_DIR$">
|
||||||
<ProjectState />
|
<ProjectState />
|
||||||
@ -28,13 +63,18 @@
|
|||||||
<option name="RECENT_TEMPLATES">
|
<option name="RECENT_TEMPLATES">
|
||||||
<list>
|
<list>
|
||||||
<option value="Kotlin Class" />
|
<option value="Kotlin Class" />
|
||||||
|
<option value="Kotlin Object" />
|
||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
|
<component name="Git.Settings">
|
||||||
|
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||||
|
</component>
|
||||||
<component name="ProjectColorInfo">{
|
<component name="ProjectColorInfo">{
|
||||||
"associatedIndex": 2
|
"associatedIndex": 2
|
||||||
}</component>
|
}</component>
|
||||||
<component name="ProjectId" id="2wKOHidxhnHfFSWY1BX7dDJxqEV" />
|
<component name="ProjectId" id="2wKOHidxhnHfFSWY1BX7dDJxqEV" />
|
||||||
|
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
|
||||||
<component name="ProjectViewState">
|
<component name="ProjectViewState">
|
||||||
<option name="hideEmptyMiddlePackages" value="true" />
|
<option name="hideEmptyMiddlePackages" value="true" />
|
||||||
<option name="showLibraryContents" value="true" />
|
<option name="showLibraryContents" value="true" />
|
||||||
@ -44,16 +84,27 @@
|
|||||||
"Android App.app.executor": "Run",
|
"Android App.app.executor": "Run",
|
||||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||||
"RunOnceActivity.cidr.known.project.marker": "true",
|
"RunOnceActivity.cidr.known.project.marker": "true",
|
||||||
|
"RunOnceActivity.git.unshallow": "true",
|
||||||
"RunOnceActivity.readMode.enableVisualFormatting": "true",
|
"RunOnceActivity.readMode.enableVisualFormatting": "true",
|
||||||
"cf.first.check.clang-format": "false",
|
"cf.first.check.clang-format": "false",
|
||||||
"cidr.known.project.marker": "true",
|
"cidr.known.project.marker": "true",
|
||||||
|
"com.google.services.firebase.aqiPopupShown": "true",
|
||||||
|
"git-widget-placeholder": "master",
|
||||||
"kotlin-language-version-configured": "true",
|
"kotlin-language-version-configured": "true",
|
||||||
"project.structure.last.edited": "Modules",
|
"project.structure.last.edited": "Modules",
|
||||||
"project.structure.proportion": "0.17",
|
"project.structure.proportion": "0.17",
|
||||||
"project.structure.side.proportion": "0.2",
|
"project.structure.side.proportion": "0.2",
|
||||||
"settings.editor.selected.configurable": "preferences.language.Kotlin"
|
"settings.editor.selected.configurable": "editor.preferences.fonts.default"
|
||||||
}
|
}
|
||||||
}]]></component>
|
}]]></component>
|
||||||
|
<component name="RecentsManager">
|
||||||
|
<key name="android.template.-2066939809">
|
||||||
|
<recent name="de.polyfish0.pamauth.activities" />
|
||||||
|
</key>
|
||||||
|
<key name="android.template.2108362692">
|
||||||
|
<recent name="de.polyfish0.pamauth.activities" />
|
||||||
|
</key>
|
||||||
|
</component>
|
||||||
<component name="RunManager">
|
<component name="RunManager">
|
||||||
<configuration name="app" type="AndroidRunConfigurationType" factoryName="Android App" activateToolWindowBeforeRun="false">
|
<configuration name="app" type="AndroidRunConfigurationType" factoryName="Android App" activateToolWindowBeforeRun="false">
|
||||||
<module name="PAM_Auth.app" />
|
<module name="PAM_Auth.app" />
|
||||||
@ -137,19 +188,67 @@
|
|||||||
<option name="presentableId" value="Default" />
|
<option name="presentableId" value="Default" />
|
||||||
<updated>1745786712844</updated>
|
<updated>1745786712844</updated>
|
||||||
</task>
|
</task>
|
||||||
|
<task id="LOCAL-00001" summary="Improve .gitignore">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1746231445912</created>
|
||||||
|
<option name="number" value="00001" />
|
||||||
|
<option name="presentableId" value="LOCAL-00001" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1746231445912</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL-00002" summary="Improve .gitignore">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1746231473505</created>
|
||||||
|
<option name="number" value="00002" />
|
||||||
|
<option name="presentableId" value="LOCAL-00002" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1746231473505</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL-00003" summary="Improve .gitignore">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1746231483427</created>
|
||||||
|
<option name="number" value="00003" />
|
||||||
|
<option name="presentableId" value="LOCAL-00003" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1746231483427</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL-00004" summary="Improve .gitignore">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1746231495331</created>
|
||||||
|
<option name="number" value="00004" />
|
||||||
|
<option name="presentableId" value="LOCAL-00004" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1746231495331</updated>
|
||||||
|
</task>
|
||||||
|
<option name="localTasksCounter" value="5" />
|
||||||
<servers />
|
<servers />
|
||||||
</component>
|
</component>
|
||||||
|
<component name="VcsManagerConfiguration">
|
||||||
|
<MESSAGE value="Improve .gitignore" />
|
||||||
|
<option name="LAST_COMMIT_MESSAGE" value="Improve .gitignore" />
|
||||||
|
</component>
|
||||||
|
<component name="XDebuggerManager">
|
||||||
|
<breakpoint-manager>
|
||||||
|
<breakpoints>
|
||||||
|
<line-breakpoint enabled="true" type="kotlin-line">
|
||||||
|
<url>file://$PROJECT_DIR$/app/src/main/java/de/polyfish0/pamauth/services/PAMServerService.kt</url>
|
||||||
|
<line>173</line>
|
||||||
|
<option name="timeStamp" value="9" />
|
||||||
|
</line-breakpoint>
|
||||||
|
</breakpoints>
|
||||||
|
</breakpoint-manager>
|
||||||
|
</component>
|
||||||
<component name="play_dynamic_filters_status">
|
<component name="play_dynamic_filters_status">
|
||||||
<option name="appIdToCheckInfo">
|
<option name="appIdToCheckInfo">
|
||||||
<map>
|
<map>
|
||||||
<entry key="de.polyfish0.pamauth">
|
<entry key="de.polyfish0.pamauth">
|
||||||
<value>
|
<value>
|
||||||
<CheckInfo lastCheckTimestamp="1745789513434" />
|
<CheckInfo lastCheckTimestamp="1746209320095" />
|
||||||
</value>
|
</value>
|
||||||
</entry>
|
</entry>
|
||||||
<entry key="de.polyfish0.pamauth.test">
|
<entry key="de.polyfish0.pamauth.test">
|
||||||
<value>
|
<value>
|
||||||
<CheckInfo lastCheckTimestamp="1745789513434" />
|
<CheckInfo lastCheckTimestamp="1746209320092" />
|
||||||
</value>
|
</value>
|
||||||
</entry>
|
</entry>
|
||||||
</map>
|
</map>
|
||||||
|
@ -2,6 +2,7 @@ plugins {
|
|||||||
alias(libs.plugins.android.application)
|
alias(libs.plugins.android.application)
|
||||||
alias(libs.plugins.kotlin.android)
|
alias(libs.plugins.kotlin.android)
|
||||||
alias(libs.plugins.kotlin.compose)
|
alias(libs.plugins.kotlin.compose)
|
||||||
|
kotlin("plugin.serialization") version "2.1.20"
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
@ -50,6 +51,13 @@ dependencies {
|
|||||||
implementation(libs.androidx.ui.tooling.preview)
|
implementation(libs.androidx.ui.tooling.preview)
|
||||||
implementation(libs.androidx.material3)
|
implementation(libs.androidx.material3)
|
||||||
implementation(libs.androidx.biometric.ktx)
|
implementation(libs.androidx.biometric.ktx)
|
||||||
|
implementation(libs.androidx.activity)
|
||||||
|
implementation(libs.androidx.activity.ktx)
|
||||||
|
implementation(libs.androidx.lifecycle.service)
|
||||||
|
implementation(libs.androidx.appcompat)
|
||||||
|
implementation(libs.material)
|
||||||
|
implementation(libs.androidx.constraintlayout)
|
||||||
|
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.0")
|
||||||
testImplementation(libs.junit)
|
testImplementation(libs.junit)
|
||||||
androidTestImplementation(libs.androidx.junit)
|
androidTestImplementation(libs.androidx.junit)
|
||||||
androidTestImplementation(libs.androidx.espresso.core)
|
androidTestImplementation(libs.androidx.espresso.core)
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools" >
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
|
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
@ -14,22 +17,30 @@
|
|||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.PAMAuth"
|
android:theme="@style/Theme.PAMAuth"
|
||||||
tools:targetApi="31">
|
tools:targetApi="31" >
|
||||||
<service
|
<activity
|
||||||
android:name=".services.PAMServerService"
|
android:name=".activities.TransparentBiometricActivity"
|
||||||
android:foregroundServiceType="dataSync"
|
android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen"
|
||||||
android:exported="false"/>
|
android:excludeFromRecents="true"
|
||||||
|
android:exported="true"
|
||||||
|
android:taskAffinity=""
|
||||||
|
android:finishOnTaskLaunch="true" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:label="@string/app_name"
|
android:theme="@style/Theme.PAMAuth" >
|
||||||
android:theme="@style/Theme.PAMAuth">
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".services.PAMServerService"
|
||||||
|
android:exported="false"
|
||||||
|
android:foregroundServiceType="dataSync" />
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
@ -1,83 +1,193 @@
|
|||||||
package de.polyfish0.pamauth
|
package de.polyfish0.pamauth
|
||||||
|
|
||||||
|
import android.app.ActivityManager
|
||||||
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.SharedPreferences
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.widget.Toast
|
import android.provider.Settings
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
import androidx.biometric.BiometricManager
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.biometric.BiometricPrompt
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.AlertDialog
|
||||||
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.ElevatedButton
|
import androidx.compose.material3.ElevatedButton
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.material3.Switch
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.DisposableEffect
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
|
import androidx.compose.runtime.State
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.edit
|
||||||
|
import androidx.core.net.toUri
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import de.polyfish0.pamauth.services.PAMServerService
|
import de.polyfish0.pamauth.services.PAMServerService
|
||||||
import de.polyfish0.pamauth.ui.theme.PAMAuthTheme
|
import de.polyfish0.pamauth.ui.theme.PAMAuthTheme
|
||||||
|
import de.polyfish0.pamauth.viewmodels.PermissionState
|
||||||
|
|
||||||
class MainActivity : FragmentActivity() {
|
class MainActivity : FragmentActivity() {
|
||||||
|
private lateinit var showNotificationDialog: MutableState<Boolean>
|
||||||
|
private lateinit var showOverlayDialog: MutableState<Boolean>
|
||||||
|
private lateinit var context: Context
|
||||||
|
private lateinit var serviceIntent: Intent
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
serviceIntent = Intent(this, PAMServerService::class.java)
|
||||||
|
|
||||||
enableEdgeToEdge()
|
enableEdgeToEdge()
|
||||||
setContent {
|
setContent {
|
||||||
PAMAuthTheme {
|
context = LocalContext.current
|
||||||
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
|
showNotificationDialog = remember { mutableStateOf(false) }
|
||||||
Greeting(
|
showOverlayDialog = remember { mutableStateOf(!Settings.canDrawOverlays(context)) }
|
||||||
name = "Android",
|
val isServiceRunning by rememberServiceRunningState()
|
||||||
modifier = Modifier.padding(innerPadding)
|
|
||||||
)
|
RequestPermission("android.permission.POST_NOTIFICATIONS") { result ->
|
||||||
ElevatedButton(
|
showNotificationDialog.value = !result
|
||||||
modifier = Modifier.padding(innerPadding),
|
}
|
||||||
onClick = { startForegroundService(Intent(this, PAMServerService::class.java)) }
|
|
||||||
) {
|
val isRunning = getSharedPreferences("pam", Context.MODE_PRIVATE).getBoolean("serviceRunning", false)
|
||||||
Text(text = "Show Biometric")
|
if (isRunning) {
|
||||||
|
if (!isServiceActuallyRunning(context)) {
|
||||||
|
getSharedPreferences("pam", Context.MODE_PRIVATE).edit {
|
||||||
|
putBoolean("serviceRunning", false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PAMAuthTheme {
|
||||||
|
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
|
||||||
|
Column(modifier = Modifier.padding(innerPadding)) {
|
||||||
|
Greeting(
|
||||||
|
name = "PAM Server for Linux authentication",
|
||||||
|
modifier = Modifier.padding(innerPadding)
|
||||||
|
)
|
||||||
|
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
|
||||||
|
Text("Service enabled")
|
||||||
|
Switch(
|
||||||
|
checked = isServiceRunning,
|
||||||
|
onCheckedChange = {
|
||||||
|
if(it) {
|
||||||
|
startForegroundService(serviceIntent)
|
||||||
|
}else {
|
||||||
|
stopService(serviceIntent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckOverlayPermission()
|
||||||
|
CheckNotificationsPermission()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showBiometric() {
|
override fun onResume() {
|
||||||
var biometricPrompt = BiometricPrompt(
|
super.onResume()
|
||||||
this,
|
PermissionState.updatePermission(applicationContext, "android.permission.POST_NOTIFICATIONS")
|
||||||
ContextCompat.getMainExecutor(this),
|
if(this::showOverlayDialog.isInitialized)
|
||||||
object : BiometricPrompt.AuthenticationCallback() {
|
showOverlayDialog.value = !Settings.canDrawOverlays(applicationContext)
|
||||||
override fun onAuthenticationError(errorCode: Int,
|
}
|
||||||
errString: CharSequence) {
|
|
||||||
super.onAuthenticationError(errorCode, errString)
|
|
||||||
Toast.makeText(applicationContext,
|
|
||||||
"Authentication error: $errString", Toast.LENGTH_SHORT)
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onAuthenticationSucceeded(
|
private fun isServiceActuallyRunning(context: Context): Boolean {
|
||||||
result: BiometricPrompt.AuthenticationResult) {
|
val manager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
|
||||||
super.onAuthenticationSucceeded(result)
|
return manager.getRunningServices(Int.MAX_VALUE).any {
|
||||||
Toast.makeText(applicationContext,
|
it.service.className == PAMServerService::class.java.name
|
||||||
"Authentication succeeded!", Toast.LENGTH_SHORT)
|
}
|
||||||
.show()
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun onAuthenticationFailed() {
|
@Composable
|
||||||
super.onAuthenticationFailed()
|
fun CheckNotificationsPermission() {
|
||||||
Toast.makeText(applicationContext, "Authentication failed",
|
if(showNotificationDialog.value and !(PermissionState.rememberPermissionState(context, "android.permission.POST_NOTIFICATIONS").value)) {
|
||||||
Toast.LENGTH_SHORT)
|
AlertDialog(
|
||||||
.show()
|
title = {
|
||||||
|
Text("Notification permission denied")
|
||||||
|
},
|
||||||
|
text = {
|
||||||
|
Text("This app needs the permission for notifications to function. If the app is not able to open the biometrics menu it sends you a notification which opens it when you tap on it.")
|
||||||
|
},
|
||||||
|
onDismissRequest = {},
|
||||||
|
confirmButton = {
|
||||||
|
Button(onClick = {
|
||||||
|
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
|
||||||
|
intent.data = "package:$packageName".toUri()
|
||||||
|
startActivity(intent)
|
||||||
|
}) {
|
||||||
|
Text("Open Settings")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
)
|
||||||
biometricPrompt.authenticate(BiometricPrompt.PromptInfo.Builder()
|
}
|
||||||
.setTitle("PAM Test")
|
}
|
||||||
.setSubtitle("PAM Subtitle")
|
|
||||||
.setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG)
|
@Composable
|
||||||
.setNegativeButtonText("Abort")
|
fun CheckOverlayPermission() {
|
||||||
.build()
|
if(showOverlayDialog.value) {
|
||||||
)
|
AlertDialog(
|
||||||
|
onDismissRequest = {},
|
||||||
|
title = { Text("Overlay permission required") },
|
||||||
|
text = {
|
||||||
|
Text("This app needs the permission to show overlays to work properly.")
|
||||||
|
},
|
||||||
|
confirmButton = {
|
||||||
|
Button(onClick = {
|
||||||
|
val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION).apply {
|
||||||
|
data = "package:${context.packageName}".toUri()
|
||||||
|
}
|
||||||
|
startActivityForResult(intent, 100)
|
||||||
|
}) {
|
||||||
|
Text("Settings")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data)
|
||||||
|
if(resultCode == 100) {
|
||||||
|
showOverlayDialog.value = !Settings.canDrawOverlays(applicationContext)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun rememberServiceRunningState(): State<Boolean> {
|
||||||
|
val state = remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
DisposableEffect(Unit) {
|
||||||
|
val prefs = getSharedPreferences("pam", Context.MODE_PRIVATE)
|
||||||
|
val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
|
||||||
|
if (key == "serviceRunning") {
|
||||||
|
state.value = prefs.getBoolean("serviceRunning", false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prefs.registerOnSharedPreferenceChangeListener(listener)
|
||||||
|
state.value = prefs.getBoolean("serviceRunning", false)
|
||||||
|
|
||||||
|
onDispose {
|
||||||
|
prefs.unregisterOnSharedPreferenceChangeListener(listener)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,4 +205,23 @@ fun GreetingPreview() {
|
|||||||
PAMAuthTheme {
|
PAMAuthTheme {
|
||||||
Greeting("Android")
|
Greeting("Android")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun RequestPermission(permission: String, onResult: (Boolean) -> Unit) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val launcher = rememberLauncherForActivityResult(
|
||||||
|
contract = ActivityResultContracts.RequestPermission()
|
||||||
|
) { isGranted ->
|
||||||
|
PermissionState.updatePermission(context, permission)
|
||||||
|
onResult(isGranted)
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
if (!PermissionState.hasPermission(context, permission)) {
|
||||||
|
launcher.launch(permission)
|
||||||
|
} else {
|
||||||
|
onResult(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,35 +1,64 @@
|
|||||||
package de.polyfish0.pamauth.services
|
package de.polyfish0.pamauth.services
|
||||||
|
|
||||||
|
import android.app.ActivityManager
|
||||||
import android.app.ForegroundServiceStartNotAllowedException
|
import android.app.ForegroundServiceStartNotAllowedException
|
||||||
import android.app.NotificationChannel
|
import android.app.NotificationChannel
|
||||||
import android.app.NotificationManager
|
import android.app.NotificationManager
|
||||||
|
import android.app.PendingIntent
|
||||||
import android.app.Service
|
import android.app.Service
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.SharedPreferences
|
||||||
import android.content.pm.ServiceInfo
|
import android.content.pm.ServiceInfo
|
||||||
|
import android.graphics.PixelFormat
|
||||||
import android.net.nsd.NsdManager
|
import android.net.nsd.NsdManager
|
||||||
import android.net.nsd.NsdServiceInfo
|
import android.net.nsd.NsdServiceInfo
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
import android.os.Handler
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
|
import android.os.Looper
|
||||||
|
import android.os.PowerManager
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.Window
|
||||||
|
import android.view.WindowManager
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.app.ServiceCompat
|
import androidx.core.app.ServiceCompat
|
||||||
|
import androidx.lifecycle.LifecycleService
|
||||||
|
import de.polyfish0.pamauth.R
|
||||||
|
import de.polyfish0.pamauth.activities.TransparentBiometricActivity
|
||||||
|
import de.polyfish0.pamauth.data.PAMRequestData
|
||||||
|
import de.polyfish0.pamauth.utils.CallbackManager
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
import java.net.ServerSocket
|
import java.net.ServerSocket
|
||||||
|
import java.net.Socket
|
||||||
|
import kotlin.uuid.ExperimentalUuidApi
|
||||||
|
import kotlin.uuid.Uuid
|
||||||
|
import androidx.core.content.edit
|
||||||
|
|
||||||
|
class PAMServerService : LifecycleService() {
|
||||||
|
private val socketMap = mutableMapOf<String, Socket>()
|
||||||
|
private lateinit var notificationManager: NotificationManager
|
||||||
|
|
||||||
class PAMServerService : Service() {
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
|
|
||||||
|
notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
|
||||||
|
|
||||||
|
getSharedPreferences("pam", Context.MODE_PRIVATE).edit {
|
||||||
|
putBoolean("serviceRunning", true)
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val channel = NotificationChannel(
|
val channel = NotificationChannel(
|
||||||
"PAMServer",
|
"PAMServer",
|
||||||
"PAM Authentication Server",
|
"PAM Authentication Server",
|
||||||
NotificationManager.IMPORTANCE_LOW
|
NotificationManager.IMPORTANCE_MAX
|
||||||
).apply {
|
).apply {
|
||||||
description = "Handles PAM authentication server foreground service"
|
description = "Handles PAM authentication server foreground service"
|
||||||
}
|
}
|
||||||
|
|
||||||
val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
|
|
||||||
notificationManager.createNotificationChannel(channel)
|
notificationManager.createNotificationChannel(channel)
|
||||||
|
|
||||||
val notification = NotificationCompat.Builder(this, "PAMServer")
|
val notification = NotificationCompat.Builder(this, "PAMServer")
|
||||||
@ -37,6 +66,7 @@ class PAMServerService : Service() {
|
|||||||
.setContentText("PAM Server is running")
|
.setContentText("PAM Server is running")
|
||||||
.setSmallIcon(android.R.drawable.ic_lock_lock)
|
.setSmallIcon(android.R.drawable.ic_lock_lock)
|
||||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||||
|
.setOngoing(true)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
ServiceCompat.startForeground(
|
ServiceCompat.startForeground(
|
||||||
@ -59,11 +89,13 @@ class PAMServerService : Service() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBind(p0: Intent?): IBinder? {
|
override fun onBind(intent: Intent): IBinder? {
|
||||||
|
super.onBind(intent)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
|
super.onStartCommand(intent, flags, startId)
|
||||||
startServer()
|
startServer()
|
||||||
|
|
||||||
return START_STICKY
|
return START_STICKY
|
||||||
@ -97,11 +129,19 @@ class PAMServerService : Service() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var nsdManager = (getSystemService(NSD_SERVICE) as NsdManager).apply {
|
(getSystemService(NSD_SERVICE) as NsdManager).apply {
|
||||||
registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD, registrationListener)
|
registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD, registrationListener)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
getSharedPreferences("pam", Context.MODE_PRIVATE).edit {
|
||||||
|
putBoolean("serviceRunning", false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalUuidApi::class)
|
||||||
private fun startServer() {
|
private fun startServer() {
|
||||||
Thread {
|
Thread {
|
||||||
try {
|
try {
|
||||||
@ -111,16 +151,64 @@ class PAMServerService : Service() {
|
|||||||
}
|
}
|
||||||
while (true) {
|
while (true) {
|
||||||
val client = serverSocket.accept()
|
val client = serverSocket.accept()
|
||||||
val input = client.getInputStream().bufferedReader()
|
|
||||||
val request = input.readLine()
|
Thread {
|
||||||
Log.d("PAM", request)
|
val input = client.getInputStream().bufferedReader()
|
||||||
client.outputStream.write("Hi $request\n".toByteArray())
|
val data = Json.decodeFromString<PAMRequestData>(input.readLine())
|
||||||
client.outputStream.flush()
|
|
||||||
client.close()
|
val callbackID = Uuid.random().toString()
|
||||||
|
CallbackManager.put(callbackID, ::test)
|
||||||
|
socketMap[callbackID] = client
|
||||||
|
|
||||||
|
val intent = Intent(applicationContext, TransparentBiometricActivity::class.java).apply {
|
||||||
|
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
|
addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)
|
||||||
|
|
||||||
|
putExtra("computerName", data.computerName)
|
||||||
|
putExtra("process", data.process)
|
||||||
|
putExtra("callbackID", callbackID)
|
||||||
|
}
|
||||||
|
if(hasAppTask(applicationContext)) {
|
||||||
|
startActivity(intent)
|
||||||
|
}else {
|
||||||
|
val notification = NotificationCompat.Builder(applicationContext, "PAMServer")
|
||||||
|
.setContentTitle("PAM Authentication request")
|
||||||
|
.setContentText("The computer \"${data.computerName}\" has requested an authentication for the process \"${data.process}\"")
|
||||||
|
.setSmallIcon(android.R.drawable.ic_lock_lock)
|
||||||
|
.setContentIntent(
|
||||||
|
PendingIntent.getActivity(
|
||||||
|
applicationContext,
|
||||||
|
0,
|
||||||
|
intent,
|
||||||
|
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.setAutoCancel(true)
|
||||||
|
.setPriority(NotificationCompat.PRIORITY_MAX)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
notificationManager.notify(callbackID.hashCode(), notification)
|
||||||
|
}
|
||||||
|
|
||||||
|
}.start()
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e("PAM", "Server error", e)
|
Log.e("PAM", "Server error", e)
|
||||||
}
|
}
|
||||||
}.start()
|
}.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun test(result: Boolean, callbackID: String) {
|
||||||
|
Thread {
|
||||||
|
val client = socketMap.remove(callbackID)?: throw RuntimeException("No client with callbackID \"$callbackID\" registered")
|
||||||
|
client.getOutputStream().write("Result: $result".toByteArray())
|
||||||
|
client.close()
|
||||||
|
}.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun hasAppTask(context: Context): Boolean {
|
||||||
|
val am = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
|
||||||
|
val tasks = am.appTasks
|
||||||
|
return tasks.any { it.taskInfo.baseIntent.component?.packageName == context.packageName }
|
||||||
|
}
|
||||||
}
|
}
|
@ -7,4 +7,5 @@
|
|||||||
<color name="teal_700">#FF018786</color>
|
<color name="teal_700">#FF018786</color>
|
||||||
<color name="black">#FF000000</color>
|
<color name="black">#FF000000</color>
|
||||||
<color name="white">#FFFFFFFF</color>
|
<color name="white">#FFFFFFFF</color>
|
||||||
|
<color name="transparent">#00000000</color>
|
||||||
</resources>
|
</resources>
|
@ -1,5 +1,12 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<style name="Theme.PAMAuth" parent="android:Theme.Material.Light.NoActionBar" />
|
<style name="Theme.PAMAuth" parent="android:Theme.Material.Light.NoActionBar" />
|
||||||
|
<style name="Theme.Transparent" parent="android:Theme">
|
||||||
|
<item name="android:windowIsTranslucent">true</item>
|
||||||
|
<item name="android:windowBackground">@android:color/transparent</item>
|
||||||
|
<item name="android:windowContentOverlay">@null</item>
|
||||||
|
<item name="android:windowNoTitle">true</item>
|
||||||
|
<item name="android:windowIsFloating">true</item>
|
||||||
|
<item name="android:backgroundDimEnabled">false</item>
|
||||||
|
</style>
|
||||||
</resources>
|
</resources>
|
@ -1,5 +1,5 @@
|
|||||||
[versions]
|
[versions]
|
||||||
agp = "8.9.1"
|
agp = "8.9.2"
|
||||||
kotlin = "2.0.21"
|
kotlin = "2.0.21"
|
||||||
coreKtx = "1.10.1"
|
coreKtx = "1.10.1"
|
||||||
junit = "4.13.2"
|
junit = "4.13.2"
|
||||||
@ -9,6 +9,9 @@ lifecycleRuntimeKtx = "2.6.1"
|
|||||||
activityCompose = "1.8.0"
|
activityCompose = "1.8.0"
|
||||||
composeBom = "2024.09.00"
|
composeBom = "2024.09.00"
|
||||||
biometricKtx = "1.4.0-alpha02"
|
biometricKtx = "1.4.0-alpha02"
|
||||||
|
appcompat = "1.6.1"
|
||||||
|
material = "1.10.0"
|
||||||
|
constraintlayout = "2.1.4"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||||
@ -26,9 +29,14 @@ androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-man
|
|||||||
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
|
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
|
||||||
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
|
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
|
||||||
androidx-biometric-ktx = { group = "androidx.biometric", name = "biometric", version.ref = "biometricKtx" }
|
androidx-biometric-ktx = { group = "androidx.biometric", name = "biometric", version.ref = "biometricKtx" }
|
||||||
|
androidx-activity = { group = "androidx.activity", name = "activity" }
|
||||||
|
androidx-activity-ktx = { group = "androidx.activity", name = "activity-ktx" }
|
||||||
|
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
|
||||||
|
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
|
||||||
|
androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
|
||||||
|
androidx-lifecycle-service = { group = "androidx.lifecycle", name = "lifecycle-service" }
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||||
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
||||||
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|
||||||
|
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
## This file is automatically generated by Android Studio.
|
## This file must *NOT* be checked into Version Control Systems,
|
||||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
|
||||||
#
|
|
||||||
# This file should *NOT* be checked into Version Control Systems,
|
|
||||||
# as it contains information specific to your local configuration.
|
# as it contains information specific to your local configuration.
|
||||||
#
|
#
|
||||||
# Location of the SDK. This is only used by Gradle.
|
# Location of the SDK. This is only used by Gradle.
|
||||||
# For customization when using a Version Control System, please read the
|
# For customization when using a Version Control System, please read the
|
||||||
# header note.
|
# header note.
|
||||||
sdk.dir=/Users/mika/Library/Android/sdk
|
#Tue Apr 29 15:43:07 UTC 2025
|
||||||
|
sdk.dir=/home/mika/Android/Sdk
|
||||||
|
Loading…
Reference in New Issue
Block a user