Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fea1a75cdf | |||
| 0dfaeef7bf | |||
| 92a7853258 | |||
| 14f22b4ebf |
@@ -45,8 +45,8 @@ Use this skill together with the installed `android-emulator-debug` skill. That
|
|||||||
## Build Workflow
|
## Build Workflow
|
||||||
|
|
||||||
1. Verify the JDK/SDK paths match the known working environment.
|
1. Verify the JDK/SDK paths match the known working environment.
|
||||||
2. Build with `make apk`.
|
2. Build with `make apk` for debug validation, or `make apk-release` when validating production signing behavior.
|
||||||
3. If `make apk` fails, inspect the effective `JAVA_HOME`, `ANDROID_SDK_ROOT`, and `ANDROID_NDK_ROOT` before changing code.
|
3. If the build fails, inspect the effective `JAVA_HOME`, `ANDROID_SDK_ROOT`, and `ANDROID_NDK_ROOT` before changing code.
|
||||||
4. If the problem is Android-only, avoid desktop-only conclusions from `go test ./...`.
|
4. If the problem is Android-only, avoid desktop-only conclusions from `go test ./...`.
|
||||||
|
|
||||||
Typical local build:
|
Typical local build:
|
||||||
@@ -55,6 +55,12 @@ Typical local build:
|
|||||||
JAVA_HOME=/usr/lib/jvm/java-25-openjdk make apk
|
JAVA_HOME=/usr/lib/jvm/java-25-openjdk make apk
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Typical local release build:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
JAVA_HOME=/usr/lib/jvm/java-25-openjdk make apk-release
|
||||||
|
```
|
||||||
|
|
||||||
## Emulator Workflow
|
## Emulator Workflow
|
||||||
|
|
||||||
1. Reuse an existing emulator session if one is already running.
|
1. Reuse an existing emulator session if one is already running.
|
||||||
@@ -79,7 +85,7 @@ adb shell dumpsys window | rg 'mCurrentFocus|mFocusedApp'
|
|||||||
|
|
||||||
## Validation Checklist
|
## Validation Checklist
|
||||||
|
|
||||||
- APK builds successfully with `make apk`.
|
- APK builds successfully with the intended target: `make apk` for debug validation or `make apk-release` for release-signing validation.
|
||||||
- App launches to `org.julianfamily.keepassgo/org.gioui.GioActivity`.
|
- App launches to `org.julianfamily.keepassgo/org.gioui.GioActivity`.
|
||||||
- Screenshot shows the expected screen, not just a black frame.
|
- Screenshot shows the expected screen, not just a black frame.
|
||||||
- `logcat` shows no app crash or Android runtime fatal error.
|
- `logcat` shows no app crash or Android runtime fatal error.
|
||||||
|
|||||||
@@ -52,11 +52,17 @@ The installed package version must correspond to the committed source, not a dir
|
|||||||
Use the repo's known-good local JDK unless the environment already proves otherwise:
|
Use the repo's known-good local JDK unless the environment already proves otherwise:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
JAVA_HOME=/usr/lib/jvm/java-25-openjdk make apk
|
JAVA_HOME=/usr/lib/jvm/java-25-openjdk make apk-release
|
||||||
```
|
```
|
||||||
|
|
||||||
If that JDK is unavailable on the current host, use the working replacement already established for the machine and say so in the closeout.
|
If that JDK is unavailable on the current host, use the working replacement already established for the machine and say so in the closeout.
|
||||||
|
|
||||||
|
- `ship it` must use the dedicated release keystore flow, not Gio's implicit debug or temporary signing path.
|
||||||
|
- The default local release-signing paths are:
|
||||||
|
`~/.config/keepassgo/android-release.keystore`
|
||||||
|
`~/.config/keepassgo/android-release.pass`
|
||||||
|
- If those files are unavailable, stop and fix signing instead of shipping a differently signed APK.
|
||||||
|
|
||||||
### 4. Zip The APK
|
### 4. Zip The APK
|
||||||
|
|
||||||
- Create the ZIP under the globally required temporary secret-safe directory.
|
- Create the ZIP under the globally required temporary secret-safe directory.
|
||||||
|
|||||||
@@ -135,11 +135,14 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
signkey_path="$(mktemp)"
|
mkdir -p build/ci-signing
|
||||||
trap 'rm -f -- "$signkey_path"' EXIT
|
signkey_path="$(pwd)/build/ci-signing/android-release.keystore"
|
||||||
|
signpass_path="$(pwd)/build/ci-signing/android-release.pass"
|
||||||
|
trap 'rm -f -- "$signkey_path" "$signpass_path"' EXIT
|
||||||
printf '%s' '${{ secrets.APK_SIGNKEY_B64 }}' | base64 -d > "$signkey_path"
|
printf '%s' '${{ secrets.APK_SIGNKEY_B64 }}' | base64 -d > "$signkey_path"
|
||||||
|
printf '%s' '${{ secrets.APK_SIGNPASS }}' > "$signpass_path"
|
||||||
export APP_VERSION="$(git describe --tags --always --dirty)"
|
export APP_VERSION="$(git describe --tags --always --dirty)"
|
||||||
make apk SIGNKEY="$signkey_path" SIGNPASS='${{ secrets.APK_SIGNPASS }}'
|
make apk-release RELEASE_SIGNKEY="$signkey_path" RELEASE_SIGNPASS_FILE="$signpass_path"
|
||||||
cp build/keepassgo.apk "${DIST_DIR}/keepassgo.apk"
|
cp build/keepassgo.apk "${DIST_DIR}/keepassgo.apk"
|
||||||
|
|
||||||
- name: Upload CI artifacts
|
- name: Upload CI artifacts
|
||||||
|
|||||||
@@ -6,11 +6,22 @@ Build the APK with:
|
|||||||
make apk
|
make apk
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Build the release-signed APK with:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make apk-release
|
||||||
|
```
|
||||||
|
|
||||||
`make apk` uses a local Java 25 install when `JAVA_HOME` points to one.
|
`make apk` uses a local Java 25 install when `JAVA_HOME` points to one.
|
||||||
If the host does not have a working Java 25 install, it falls back to the
|
If the host does not have a working Java 25 install, it falls back to the
|
||||||
repo-managed Docker image in `packaging/docker/android-apk/`, which also builds
|
repo-managed Docker image in `packaging/docker/android-apk/`, which also builds
|
||||||
with Java 25.
|
with Java 25.
|
||||||
|
|
||||||
|
`make apk` remains a developer build path and may use Gio's default debug or
|
||||||
|
ephemeral signing behavior if no explicit signing key is provided.
|
||||||
|
`make apk-release` is the production-signing path and fails unless a dedicated
|
||||||
|
release keystore and password file are present.
|
||||||
|
|
||||||
Environment:
|
Environment:
|
||||||
|
|
||||||
- `ANDROID_SDK_ROOT` defaults to `/opt/android-sdk`.
|
- `ANDROID_SDK_ROOT` defaults to `/opt/android-sdk`.
|
||||||
@@ -23,6 +34,14 @@ Environment:
|
|||||||
- `APK_VERSION` overrides the packaged app version.
|
- `APK_VERSION` overrides the packaged app version.
|
||||||
- `ANDROID_MIN_SDK` overrides the minimum supported Android SDK.
|
- `ANDROID_MIN_SDK` overrides the minimum supported Android SDK.
|
||||||
- `ANDROID_TARGET_SDK` overrides the target Android SDK.
|
- `ANDROID_TARGET_SDK` overrides the target Android SDK.
|
||||||
|
- `SIGNPASS_FILE` provides the signing password by file instead of a command-line argument.
|
||||||
|
- `RELEASE_SIGNKEY` overrides the release keystore path used by `make apk-release`.
|
||||||
|
- `RELEASE_SIGNPASS_FILE` overrides the password file path used by `make apk-release`.
|
||||||
|
|
||||||
|
Default release-signing paths:
|
||||||
|
|
||||||
|
- `~/.config/keepassgo/android-release.keystore`
|
||||||
|
- `~/.config/keepassgo/android-release.pass`
|
||||||
|
|
||||||
Installed machine prerequisites expected by this repo:
|
Installed machine prerequisites expected by this repo:
|
||||||
|
|
||||||
@@ -38,6 +57,10 @@ The repo tracks `gogio` as a Go tool, and the local build runs through:
|
|||||||
go tool gogio -target android ./cmd/keepassgo ...
|
go tool gogio -target android ./cmd/keepassgo ...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The release target wraps `make apk` and injects explicit signing credentials so
|
||||||
|
local release builds and CI use the same stable key without echoing the release
|
||||||
|
password in build logs.
|
||||||
|
|
||||||
The Android build uses the branded icon asset at:
|
The Android build uses the branded icon asset at:
|
||||||
|
|
||||||
- `internal/assets/keepassgo-icon.png`
|
- `internal/assets/keepassgo-icon.png`
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ ANDROID_MIN_SDK ?= 28
|
|||||||
ANDROID_TARGET_SDK ?= 35
|
ANDROID_TARGET_SDK ?= 35
|
||||||
SIGNKEY ?=
|
SIGNKEY ?=
|
||||||
SIGNPASS ?=
|
SIGNPASS ?=
|
||||||
|
SIGNPASS_FILE ?=
|
||||||
|
RELEASE_SIGNKEY ?= $(HOME)/.config/keepassgo/android-release.keystore
|
||||||
|
RELEASE_SIGNPASS_FILE ?= $(HOME)/.config/keepassgo/android-release.pass
|
||||||
ARCH_PKG_DIR ?= packaging/archlinux/keepassgo-git
|
ARCH_PKG_DIR ?= packaging/archlinux/keepassgo-git
|
||||||
ARCH_PKG_TMPL ?= $(ARCH_PKG_DIR)/PKGBUILD.tmpl
|
ARCH_PKG_TMPL ?= $(ARCH_PKG_DIR)/PKGBUILD.tmpl
|
||||||
ARCH_PKGBUILD ?= $(ARCH_PKG_DIR)/PKGBUILD
|
ARCH_PKGBUILD ?= $(ARCH_PKG_DIR)/PKGBUILD
|
||||||
@@ -26,7 +29,22 @@ ifneq ($(strip $(SIGNPASS)),)
|
|||||||
GOGIO_SIGN_FLAGS += -signpass $(SIGNPASS)
|
GOGIO_SIGN_FLAGS += -signpass $(SIGNPASS)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
.PHONY: apk apk-local apk-container apk-container-image archlinux-pkgbuild browser-bridge browser-extension-validate
|
CONTAINER_SIGNKEY_MOUNT :=
|
||||||
|
CONTAINER_SIGNPASSFILE_MOUNT :=
|
||||||
|
CONTAINER_SIGN_ARGS :=
|
||||||
|
ifneq ($(strip $(SIGNKEY)),)
|
||||||
|
CONTAINER_SIGNKEY_MOUNT += -v "$(dir $(abspath $(SIGNKEY))):$(dir $(abspath $(SIGNKEY))):ro"
|
||||||
|
CONTAINER_SIGN_ARGS += SIGNKEY="$(abspath $(SIGNKEY))"
|
||||||
|
endif
|
||||||
|
ifneq ($(strip $(SIGNPASS)),)
|
||||||
|
CONTAINER_SIGN_ARGS += SIGNPASS="$(SIGNPASS)"
|
||||||
|
endif
|
||||||
|
ifneq ($(strip $(SIGNPASS_FILE)),)
|
||||||
|
CONTAINER_SIGNPASSFILE_MOUNT += -v "$(dir $(abspath $(SIGNPASS_FILE))):$(dir $(abspath $(SIGNPASS_FILE))):ro"
|
||||||
|
CONTAINER_SIGN_ARGS += SIGNPASS_FILE="$(abspath $(SIGNPASS_FILE))"
|
||||||
|
endif
|
||||||
|
|
||||||
|
.PHONY: apk apk-local apk-release apk-container apk-container-image archlinux-pkgbuild browser-bridge browser-extension-validate
|
||||||
apk:
|
apk:
|
||||||
@if [ -x "$(JAVA_HOME)/bin/java" ] && "$(JAVA_HOME)/bin/java" -version 2>&1 | grep -q 'version "25'; then \
|
@if [ -x "$(JAVA_HOME)/bin/java" ] && "$(JAVA_HOME)/bin/java" -version 2>&1 | grep -q 'version "25'; then \
|
||||||
$(MAKE) apk-local JAVA_HOME="$(JAVA_HOME)"; \
|
$(MAKE) apk-local JAVA_HOME="$(JAVA_HOME)"; \
|
||||||
@@ -43,6 +61,12 @@ apk-local: android/keepassgo-android.jar
|
|||||||
@test -d "$(ANDROID_SDK_ROOT)/platforms/android-$(ANDROID_TARGET_SDK)" || { echo "Android platform android-$(ANDROID_TARGET_SDK) is missing"; exit 1; }
|
@test -d "$(ANDROID_SDK_ROOT)/platforms/android-$(ANDROID_TARGET_SDK)" || { echo "Android platform android-$(ANDROID_TARGET_SDK) is missing"; exit 1; }
|
||||||
@test -d "$(ANDROID_SDK_ROOT)/build-tools" || { echo "Android build-tools are missing"; exit 1; }
|
@test -d "$(ANDROID_SDK_ROOT)/build-tools" || { echo "Android build-tools are missing"; exit 1; }
|
||||||
@mkdir -p "$(dir $(APK_OUT))"
|
@mkdir -p "$(dir $(APK_OUT))"
|
||||||
|
@set -eu; \
|
||||||
|
if [ -n "$(SIGNPASS_FILE)" ]; then \
|
||||||
|
test -f "$(SIGNPASS_FILE)" || { echo "SIGNPASS_FILE does not exist: $(SIGNPASS_FILE)"; exit 1; }; \
|
||||||
|
export GOGIO_SIGNPASS="$$(tr -d '\r\n' < "$(SIGNPASS_FILE)")"; \
|
||||||
|
test -n "$$GOGIO_SIGNPASS" || { echo "SIGNPASS_FILE is empty: $(SIGNPASS_FILE)"; exit 1; }; \
|
||||||
|
fi; \
|
||||||
ANDROID_HOME="$(ANDROID_SDK_ROOT)" \
|
ANDROID_HOME="$(ANDROID_SDK_ROOT)" \
|
||||||
ANDROID_SDK_ROOT="$(ANDROID_SDK_ROOT)" \
|
ANDROID_SDK_ROOT="$(ANDROID_SDK_ROOT)" \
|
||||||
ANDROID_NDK_ROOT="$(ANDROID_NDK_ROOT)" \
|
ANDROID_NDK_ROOT="$(ANDROID_NDK_ROOT)" \
|
||||||
@@ -59,6 +83,11 @@ apk-local: android/keepassgo-android.jar
|
|||||||
-icon internal/assets/keepassgo-icon.png \
|
-icon internal/assets/keepassgo-icon.png \
|
||||||
./cmd/keepassgo
|
./cmd/keepassgo
|
||||||
|
|
||||||
|
apk-release:
|
||||||
|
@test -f "$(RELEASE_SIGNKEY)" || { echo "Release signing key not found at $(RELEASE_SIGNKEY)"; exit 1; }
|
||||||
|
@test -f "$(RELEASE_SIGNPASS_FILE)" || { echo "Release signing password file not found at $(RELEASE_SIGNPASS_FILE)"; exit 1; }
|
||||||
|
@$(MAKE) apk SIGNKEY="$(abspath $(RELEASE_SIGNKEY))" SIGNPASS_FILE="$(abspath $(RELEASE_SIGNPASS_FILE))"
|
||||||
|
|
||||||
apk-container: apk-container-image
|
apk-container: apk-container-image
|
||||||
@command -v docker >/dev/null 2>&1 || { echo "docker is required for apk-container"; exit 1; }
|
@command -v docker >/dev/null 2>&1 || { echo "docker is required for apk-container"; exit 1; }
|
||||||
@test -d "$(ANDROID_SDK_ROOT)" || { echo "ANDROID_SDK_ROOT must point to an Android SDK install"; exit 1; }
|
@test -d "$(ANDROID_SDK_ROOT)" || { echo "ANDROID_SDK_ROOT must point to an Android SDK install"; exit 1; }
|
||||||
@@ -69,11 +98,13 @@ apk-container: apk-container-image
|
|||||||
-w "$(CURDIR)" \
|
-w "$(CURDIR)" \
|
||||||
-v "$(ANDROID_SDK_ROOT):$(ANDROID_SDK_ROOT)" \
|
-v "$(ANDROID_SDK_ROOT):$(ANDROID_SDK_ROOT)" \
|
||||||
-v "$(ANDROID_NDK_ROOT):$(ANDROID_NDK_ROOT)" \
|
-v "$(ANDROID_NDK_ROOT):$(ANDROID_NDK_ROOT)" \
|
||||||
|
$(CONTAINER_SIGNKEY_MOUNT) \
|
||||||
|
$(CONTAINER_SIGNPASSFILE_MOUNT) \
|
||||||
-e ANDROID_SDK_ROOT="$(ANDROID_SDK_ROOT)" \
|
-e ANDROID_SDK_ROOT="$(ANDROID_SDK_ROOT)" \
|
||||||
-e ANDROID_NDK_ROOT="$(ANDROID_NDK_ROOT)" \
|
-e ANDROID_NDK_ROOT="$(ANDROID_NDK_ROOT)" \
|
||||||
-e JAVA_HOME=/opt/java/openjdk \
|
-e JAVA_HOME=/opt/java/openjdk \
|
||||||
$(APK_BUILD_IMAGE) \
|
$(APK_BUILD_IMAGE) \
|
||||||
make apk-local JAVA_HOME=/opt/java/openjdk
|
make apk-local JAVA_HOME=/opt/java/openjdk $(CONTAINER_SIGN_ARGS)
|
||||||
|
|
||||||
apk-container-image:
|
apk-container-image:
|
||||||
@command -v docker >/dev/null 2>&1 || { echo "docker is required for apk-container-image"; exit 1; }
|
@command -v docker >/dev/null 2>&1 || { echo "docker is required for apk-container-image"; exit 1; }
|
||||||
|
|||||||
@@ -98,6 +98,17 @@ available, it falls back to the repo-managed Docker build image, which also
|
|||||||
uses Java 25. You still need the Android SDK and NDK installed and configured
|
uses Java 25. You still need the Android SDK and NDK installed and configured
|
||||||
for real device or release packaging.
|
for real device or release packaging.
|
||||||
|
|
||||||
|
Release package:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make apk-release
|
||||||
|
```
|
||||||
|
|
||||||
|
`make apk-release` is the production-signing path. It requires a dedicated
|
||||||
|
release keystore at `~/.config/keepassgo/android-release.keystore` and a
|
||||||
|
password file at `~/.config/keepassgo/android-release.pass`, unless you
|
||||||
|
override `RELEASE_SIGNKEY` and `RELEASE_SIGNPASS_FILE`.
|
||||||
|
|
||||||
## Automation
|
## Automation
|
||||||
|
|
||||||
Desktop automation is resolved through the secure gRPC API rather than synthetic auto-type.
|
Desktop automation is resolved through the secure gRPC API rather than synthetic auto-type.
|
||||||
|
|||||||
@@ -45,6 +45,9 @@
|
|||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<data android:mimeType="application/octet-stream" />
|
||||||
|
<data android:mimeType="application/x-keepass2" />
|
||||||
|
<data android:mimeType="application/vnd.keepass" />
|
||||||
<data android:scheme="content" android:pathPattern=".*\\.kdbx" />
|
<data android:scheme="content" android:pathPattern=".*\\.kdbx" />
|
||||||
<data android:scheme="file" android:pathPattern=".*\\.kdbx" />
|
<data android:scheme="file" android:pathPattern=".*\\.kdbx" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.julianfamily.keepassgo;
|
package org.julianfamily.keepassgo;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.content.ClipData;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
@@ -10,9 +11,11 @@ import android.util.Log;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public final class SharedVaultImportActivity extends Activity {
|
public final class SharedVaultImportActivity extends Activity {
|
||||||
private static final String TAG = "KeePassGOImport";
|
private static final String TAG = "KeePassGOImport";
|
||||||
@@ -36,6 +39,7 @@ public final class SharedVaultImportActivity extends Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void handleIntent(Intent intent) {
|
private void handleIntent(Intent intent) {
|
||||||
|
logIntent(intent);
|
||||||
Uri uri = resolveSharedUri(intent);
|
Uri uri = resolveSharedUri(intent);
|
||||||
if (uri == null) {
|
if (uri == null) {
|
||||||
Log.i(TAG, "no shared vault URI on intent");
|
Log.i(TAG, "no shared vault URI on intent");
|
||||||
@@ -55,10 +59,29 @@ public final class SharedVaultImportActivity extends Activity {
|
|||||||
}
|
}
|
||||||
String action = intent.getAction();
|
String action = intent.getAction();
|
||||||
if (Intent.ACTION_SEND.equals(action)) {
|
if (Intent.ACTION_SEND.equals(action)) {
|
||||||
return intent.getParcelableExtra(Intent.EXTRA_STREAM);
|
Uri extraStream = intent.getParcelableExtra(Intent.EXTRA_STREAM);
|
||||||
|
if (extraStream != null) {
|
||||||
|
return extraStream;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Intent.ACTION_SEND_MULTIPLE.equals(action)) {
|
||||||
|
ArrayList<Uri> streams = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
|
||||||
|
if (streams != null && !streams.isEmpty()) {
|
||||||
|
return streams.get(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (Intent.ACTION_VIEW.equals(action)) {
|
if (Intent.ACTION_VIEW.equals(action)) {
|
||||||
return intent.getData();
|
Uri data = intent.getData();
|
||||||
|
if (data != null) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ClipData clipData = intent.getClipData();
|
||||||
|
if (clipData != null && clipData.getItemCount() > 0) {
|
||||||
|
Uri clipUri = clipData.getItemAt(0).getUri();
|
||||||
|
if (clipUri != null) {
|
||||||
|
return clipUri;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -69,7 +92,7 @@ public final class SharedVaultImportActivity extends Activity {
|
|||||||
throw new IOException("failed to create " + dir.getAbsolutePath());
|
throw new IOException("failed to create " + dir.getAbsolutePath());
|
||||||
}
|
}
|
||||||
File pendingFile = new File(dir, "pending-shared-vault.kdbx");
|
File pendingFile = new File(dir, "pending-shared-vault.kdbx");
|
||||||
try (InputStream in = getContentResolver().openInputStream(uri)) {
|
try (InputStream in = openSharedInputStream(uri)) {
|
||||||
if (in == null) {
|
if (in == null) {
|
||||||
throw new IOException("failed to open shared vault stream");
|
throw new IOException("failed to open shared vault stream");
|
||||||
}
|
}
|
||||||
@@ -88,6 +111,17 @@ public final class SharedVaultImportActivity extends Activity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private InputStream openSharedInputStream(Uri uri) throws IOException {
|
||||||
|
if ("file".equalsIgnoreCase(uri.getScheme())) {
|
||||||
|
String path = uri.getPath();
|
||||||
|
if (path == null || path.trim().isEmpty()) {
|
||||||
|
throw new IOException("file URI is missing a path");
|
||||||
|
}
|
||||||
|
return new FileInputStream(new File(path));
|
||||||
|
}
|
||||||
|
return getContentResolver().openInputStream(uri);
|
||||||
|
}
|
||||||
|
|
||||||
private String resolveDisplayName(Uri uri) {
|
private String resolveDisplayName(Uri uri) {
|
||||||
String displayName = queryDisplayName(uri);
|
String displayName = queryDisplayName(uri);
|
||||||
if (!displayName.isEmpty()) {
|
if (!displayName.isEmpty()) {
|
||||||
@@ -123,6 +157,20 @@ public final class SharedVaultImportActivity extends Activity {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void logIntent(Intent intent) {
|
||||||
|
if (intent == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Log.i(TAG, "intent action=" + intent.getAction()
|
||||||
|
+ " type=" + intent.getType()
|
||||||
|
+ " data=" + intent.getData()
|
||||||
|
+ " flags=0x" + Integer.toHexString(intent.getFlags()));
|
||||||
|
ClipData clipData = intent.getClipData();
|
||||||
|
if (clipData != null) {
|
||||||
|
Log.i(TAG, "intent clip items=" + clipData.getItemCount());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void launchMainActivity() {
|
private void launchMainActivity() {
|
||||||
Intent launch = new Intent();
|
Intent launch = new Intent();
|
||||||
launch.setClassName(this, "org.gioui.GioActivity");
|
launch.setClassName(this, "org.gioui.GioActivity");
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ go 1.26
|
|||||||
|
|
||||||
replace gioui.org => git.julianfamily.org/joejulian/gio-patched v0.9.1-0.20260416220049-9bfa6bc1c2dc
|
replace gioui.org => git.julianfamily.org/joejulian/gio-patched v0.9.1-0.20260416220049-9bfa6bc1c2dc
|
||||||
|
|
||||||
replace gioui.org/cmd => git.julianfamily.org/joejulian/gio-cmd-patched v0.9.1-0.20260416154203-192acd9d09b0
|
replace gioui.org/cmd => git.julianfamily.org/joejulian/gio-cmd-patched v0.9.1-0.20260417040456-1762d36ddecc
|
||||||
|
|
||||||
require (
|
require (
|
||||||
gioui.org v0.9.0
|
gioui.org v0.9.0
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ gioui.org/shader v1.0.8 h1:6ks0o/A+b0ne7RzEqRZK5f4Gboz2CfG+mVliciy6+qA=
|
|||||||
gioui.org/shader v1.0.8/go.mod h1:mWdiME581d/kV7/iEhLmUgUK5iZ09XR5XpduXzbePVM=
|
gioui.org/shader v1.0.8/go.mod h1:mWdiME581d/kV7/iEhLmUgUK5iZ09XR5XpduXzbePVM=
|
||||||
gioui.org/x v0.8.0 h1:RhIlQNOFKKn8D8FeaKKaXCo7vB3x+fq4VcD10HW/YpA=
|
gioui.org/x v0.8.0 h1:RhIlQNOFKKn8D8FeaKKaXCo7vB3x+fq4VcD10HW/YpA=
|
||||||
gioui.org/x v0.8.0/go.mod h1:aXtQb+kyqoUOjDl5/uMqAopjzVzMkeHBbMQOGT5KnSE=
|
gioui.org/x v0.8.0/go.mod h1:aXtQb+kyqoUOjDl5/uMqAopjzVzMkeHBbMQOGT5KnSE=
|
||||||
git.julianfamily.org/joejulian/gio-cmd-patched v0.9.1-0.20260416154203-192acd9d09b0 h1:jZmX7CRuev3KrOW0yB2VQDtCrzRa4Q+qWcl3CGXq2sE=
|
git.julianfamily.org/joejulian/gio-cmd-patched v0.9.1-0.20260417040456-1762d36ddecc h1:jyfCTx9wk/uLaEMkdKsg491C/kjfbG2EKAVTORhZxHo=
|
||||||
git.julianfamily.org/joejulian/gio-cmd-patched v0.9.1-0.20260416154203-192acd9d09b0/go.mod h1:RBQfFU8JCgMjQ2wKU9DG3zMC38TnY97E5MKoBGhGl3s=
|
git.julianfamily.org/joejulian/gio-cmd-patched v0.9.1-0.20260417040456-1762d36ddecc/go.mod h1:RBQfFU8JCgMjQ2wKU9DG3zMC38TnY97E5MKoBGhGl3s=
|
||||||
git.julianfamily.org/joejulian/gio-patched v0.9.1-0.20260416220049-9bfa6bc1c2dc h1:p2AaZUAXa/ExPybNyeB05+GjTSZGA9lCfDpWz49IT5Y=
|
git.julianfamily.org/joejulian/gio-patched v0.9.1-0.20260416220049-9bfa6bc1c2dc h1:p2AaZUAXa/ExPybNyeB05+GjTSZGA9lCfDpWz49IT5Y=
|
||||||
git.julianfamily.org/joejulian/gio-patched v0.9.1-0.20260416220049-9bfa6bc1c2dc/go.mod h1:BdI7mF5DCa3kxlo3G93XHL7khtZnk1gu4335pExk8gs=
|
git.julianfamily.org/joejulian/gio-patched v0.9.1-0.20260416220049-9bfa6bc1c2dc/go.mod h1:BdI7mF5DCa3kxlo3G93XHL7khtZnk1gu4335pExk8gs=
|
||||||
git.wow.st/gmp/jni v0.0.0-20210610011705-34026c7e22d0 h1:bGG/g4ypjrCJoSvFrP5hafr9PPB5aw8SjcOWWila7ZI=
|
git.wow.st/gmp/jni v0.0.0-20210610011705-34026c7e22d0 h1:bGG/g4ypjrCJoSvFrP5hafr9PPB5aw8SjcOWWila7ZI=
|
||||||
|
|||||||
Reference in New Issue
Block a user