passgo/cmd/passgo-gui/impl_android.go
Greg Pomerantz dc7661e226 Android: launch the 'All files access' settings screen at startup.
MANAGE_EXTERNAL_STORAGE (needed to read the store at
/storage/emulated/0/...) cannot be requested with a runtime
permission dialog; the user must toggle it in system settings.
Port the mechanism from the pad app:

- Permissions.java: a Fragment registered at window attach that
  launches Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION
  (per-app settings screen) when Environment.isExternalStorageManager()
  is false on API 30+ (runtime READ_EXTERNAL_STORAGE request on
  older APIs). The guard means the screen appears only until the
  user grants it.
- The compiled classes ship in PgpConnect.jar's directory jar
  (Permissions.jar); gogio picks *.jar up from the package dir and
  dexes them. go:generate now rebuilds it.
- jni_android.c/h: registerPermissionsFragment(), mirroring
  registerFragment() for PgpConnect.
- Impl wiring: call it from the AndroidViewEvent handler right
  after InitPgp.

Verified on the x86_64 emulator: with the appop denied the system
settings screen opens automatically on launch; after granting it,
launch is clean and list + OpenKeychain decryption from
/sdcard/Pass work end to end.
2026-08-21 14:44:38 -04:00

65 lines
1.2 KiB
Go

//go:build android
package main
import (
"os"
"gioui.org/app"
"gioui.org/io/event"
"git.wow.st/gmp/passgo"
)
var (
noidLabelText = "Enter a GPG key ID above"
)
func init() {
log(Info, "Android start")
// Use a larger font on Android
fontSize = 24
}
func handleEvent(e event.Event) {
switch e := e.(type) {
case app.AndroidViewEvent:
// A zero View means the view is detached (e.g. the activity going
// away on a recents-wipe); there is nothing to register for a
// detached view. A re-attach arrives as a fresh event with a live
// view.
if e.View != 0 {
initPgp(e.View)
initPermissions(e.View)
}
}
}
func initPgp(view uintptr) {
passgo.InitPgp(view)
}
func initPermissions(view uintptr) {
passgo.InitPermissions(view)
}
func getConfDir() (string, error) {
ret, err := app.DataDir()
if err != nil {
log(Error, "Cannot get data directory:", err)
return "", err
}
if _, err := os.Stat(ret); os.IsNotExist(err) {
err = os.MkdirAll(ret, 0700)
if err != nil {
log(Error, "Cannot create configuration directory ", ret)
return "", err
} else {
log(Info, "Configuration directory created")
return ret, nil
}
} else {
log(Info, "Configuration directory found")
return ret, nil
}
}