Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ A android app that take down the headache of remembering passwords. It is open s
help you in keeping your passwords safe and secure, in your own local storage without ever needing
to push them to cloud.

[Visit Website](https://jeeldobariya38.github.io/Passcodes-Website/)
[Visit Website](https://passcodesapp.github.io/Passcodes-Website/)

> What we think of passcodes?
> Password management is one such thing that is as simple as remember a password yet, it very
Expand Down Expand Up @@ -53,7 +53,7 @@ Note: high versions can still run, but we are not guaranteed offically.
- [ ] Intuitive UI.
- [ ] Update Checkers & Manager.
- [x] Password Management. (Current Priority)
- [x] Autofill.
- [x] Autofill. (as preview feature)
- [ ] Secure File. (Least Priority, Because it include permission. Which, I am as developer not
familiar with 😂)
- Could be Image. (JPG. PNG ....)
Expand Down
4 changes: 4 additions & 0 deletions autofill/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,16 @@ android {
}

dependencies {
implementation(projects.core)
implementation(projects.database)

implementation(libs.androidx.core.ktx)
implementation(libs.appcompat)
implementation(libs.material)

// Datastore Preferences
implementation(libs.androidx.datastore.preferences)

// Data/Persistence (Room Bundle)
ksp(libs.room.compiler)
implementation(libs.room.ktx)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.jeeldobariya.passcodes.autofill

import android.app.assist.AssistStructure
import android.content.Context
import android.os.CancellationSignal
import android.service.autofill.AutofillService
import android.service.autofill.FillCallback
Expand All @@ -11,6 +12,7 @@ import android.service.autofill.SaveInfo
import android.service.autofill.SaveRequest
import android.view.autofill.AutofillValue
import android.widget.RemoteViews
import com.jeeldobariya.passcodes.core.feature_flags.featureFlagsDatastore
import com.jeeldobariya.passcodes.database.master.PasswordEntity
import com.jeeldobariya.passcodes.database.master.PasswordsDao
import kotlinx.coroutines.CoroutineScope
Expand All @@ -19,6 +21,7 @@ import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject


// TODO: Docs for this autofill is need in @github:PasscodesApp/Passcodes-Docs
class PasswordAutofillService : AutofillService() {

Expand All @@ -29,30 +32,36 @@ class PasswordAutofillService : AutofillService() {
cancellationSignal: CancellationSignal,
callback: FillCallback
) {
val context = request.fillContexts
val structure = context.last().structure
cancellationSignal.setOnCancelListener {
// TODO: Handle cancellation
}

val viewNodes = mutableMapOf<String, AssistStructure.ViewNode>()
parseStructure(structure.getWindowNodeAt(0).rootViewNode, viewNodes)
serviceScope.launch {
if (!isAutofillFeaturesEnabled()) {
callback.onSuccess(null)
return@launch
}

// TODO: Add support for newUsername & newPassword autofill hints.
// https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_NEW_USERNAME()
val usernameNode = viewNodes["username"] ?: viewNodes["emailAddress"]
val passwordNode = viewNodes["password"]
val context = request.fillContexts
val structure = context.last().structure

if (usernameNode?.autofillId == null || passwordNode?.autofillId == null) {
callback.onSuccess(null)
return
}
val viewNodes = mutableMapOf<String, AssistStructure.ViewNode>()
parseStructure(structure.getWindowNodeAt(0).rootViewNode, viewNodes)

val usernameId = usernameNode.autofillId!!
val passwordId = passwordNode.autofillId!!
// TODO: Add support for newUsername & newPassword autofill hints.
// https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_NEW_USERNAME()
val usernameNode = viewNodes["username"] ?: viewNodes["emailAddress"]
val passwordNode = viewNodes["password"]

if (usernameNode?.autofillId == null || passwordNode?.autofillId == null) {
callback.onSuccess(null)
return@launch
}

val usernameId = usernameNode.autofillId!!
val passwordId = passwordNode.autofillId!!

cancellationSignal.setOnCancelListener {
// TODO: Handle cancellation
}

serviceScope.launch {
val passwordsDao by inject<PasswordsDao>()
val passwords = passwordsDao.getAllPasswords().first()
val responseBuilder = FillResponse.Builder()
Expand Down Expand Up @@ -90,35 +99,44 @@ class PasswordAutofillService : AutofillService() {
}

override fun onSaveRequest(request: SaveRequest, callback: SaveCallback) {
val context = request.fillContexts
val structure = context.last().structure
serviceScope.launch {
if (!isAutofillFeaturesEnabled()) {
// developer note: failure is sent cuz, we are not saving the incoming credentials. so, android can let user know something is off...
callback.onFailure(getString(R.string.autofill_feature_are_not_enabled))
return@launch
}

val context = request.fillContexts
val structure = context.last().structure
val packageName = structure.activityComponent.packageName

val viewNodes = mutableMapOf<String, AssistStructure.ViewNode>()
parseStructure(structure.getWindowNodeAt(0).rootViewNode, viewNodes)

// TODO: Add support for newUsername & newPassword autofill hints.
val usernameNode = viewNodes["username"] ?: viewNodes["emailAddress"]
val passwordNode = viewNodes["password"]
val viewNodes = mutableMapOf<String, AssistStructure.ViewNode>()
parseStructure(structure.getWindowNodeAt(0).rootViewNode, viewNodes)

val username = usernameNode?.text?.toString()
val password = passwordNode?.text?.toString()
// TODO: Add support for newUsername & newPassword autofill hints.
val usernameNode = viewNodes["username"] ?: viewNodes["emailAddress"]
val passwordNode = viewNodes["password"]

val username = usernameNode?.text?.toString()
val password = passwordNode?.text?.toString()

if (!username.isNullOrEmpty() && !password.isNullOrEmpty()) {

if (!username.isNullOrEmpty() && !password.isNullOrEmpty()) {
serviceScope.launch {
val passwordsDao by inject<PasswordsDao>()
passwordsDao.insertPassword(
PasswordEntity(
domain = "Autofill",
username = username,
password = password,
notes = "Save using autofill service..."
notes = "Save using autofill service...\nIdentifier(maybe): $packageName"
)
)
}

callback.onSuccess()
} else {
callback.onFailure(getString(R.string.could_not_save_credentials))
callback.onSuccess()
} else {
callback.onFailure(getString(R.string.could_not_save_credentials))
}
}
}

Expand All @@ -136,4 +154,8 @@ class PasswordAutofillService : AutofillService() {
parseStructure(node.getChildAt(i), viewNodes)
}
}

private suspend fun Context.isAutofillFeaturesEnabled(): Boolean {
return this.featureFlagsDatastore.data.first().isPreviewFeaturesEnabled
}
}
1 change: 1 addition & 0 deletions autofill/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@
<string name="open_settings">Open Settings</string>
<string name="passcodes_autofill_is_preview_feature">Passcodes Autofill is preview feature and shouldn\'t be use in production!!</string>
<string name="could_not_save_credentials">Could not save credentials.</string>
<string name="autofill_feature_are_not_enabled">Autofill feature are not enabled!!</string>
</resources>
Loading