Download one OTA APK and open Downloads

This commit is contained in:
TCFDONMEZ
2026-09-30 11:27:14 +03:00
parent 25abf0da5b
commit 634a374ea7
4 changed files with 36 additions and 31 deletions
+1
View File
@@ -0,0 +1 @@
3a3a782523a7da5d71b8b50829fce19b48008177c0df4d808aca441b7395d1d3 FatihsMG4-unstable-2.2.20.apk
+2 -2
View File
@@ -34,8 +34,8 @@ android {
applicationId "com.evsuite.abrp" applicationId "com.evsuite.abrp"
minSdk 27 minSdk 27
targetSdk 36 targetSdk 36
versionCode 36 versionCode 37
versionName "2.2.19" versionName "2.2.20"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }
@@ -337,7 +337,7 @@ final class OtaUpdater {
String safe = (versionName == null || versionName.isEmpty()) String safe = (versionName == null || versionName.isEmpty())
? "unknown" ? "unknown"
: versionName.toLowerCase(Locale.US).replaceAll("[^a-z0-9._-]", "_"); : versionName.toLowerCase(Locale.US).replaceAll("[^a-z0-9._-]", "_");
return "EVABRPUploader-unstable-" + safe + ".apk"; return safe + ".apk";
} }
/** /**
@@ -381,25 +381,20 @@ final class OtaUpdater {
Thread.sleep(250L); Thread.sleep(250L);
} }
File staged = new File(context.getCacheDir(), CACHE_PREFIX
+ java.util.UUID.randomUUID() + ".apk");
MessageDigest digest = MessageDigest.getInstance("SHA-256"); MessageDigest digest = MessageDigest.getInstance("SHA-256");
try (ParcelFileDescriptor descriptor = manager.openDownloadedFile(downloadId); try (ParcelFileDescriptor descriptor = manager.openDownloadedFile(downloadId);
java.io.InputStream input = new ParcelFileDescriptor.AutoCloseInputStream(descriptor); java.io.InputStream input = new ParcelFileDescriptor.AutoCloseInputStream(descriptor)) {
FileOutputStream output = new FileOutputStream(staged)) {
byte[] buffer = new byte[64 * 1024]; byte[] buffer = new byte[64 * 1024];
int count; int count;
while ((count = input.read(buffer)) != -1) { while ((count = input.read(buffer)) != -1) {
output.write(buffer, 0, count);
digest.update(buffer, 0, count); digest.update(buffer, 0, count);
} }
output.getFD().sync();
} }
if (!hex(digest.digest()).equalsIgnoreCase(expectedSha256)) { if (!hex(digest.digest()).equalsIgnoreCase(expectedSha256)) {
staged.delete(); if (!publicFile.delete()) Log.w(TAG, "Could not remove invalid OTA file");
return null; return null;
} }
return staged; return publicFile;
} catch (Exception e) { } catch (Exception e) {
Log.w(TAG, "Update download failed", e); Log.w(TAG, "Update download failed", e);
} }
@@ -412,6 +407,32 @@ final class OtaUpdater {
return out.toString(); return out.toString();
} }
/** Opens Android's document UI directly in Downloads; the driver chooses the APK. */
static boolean openDownloads(Context context) {
Intent picker = new Intent(Intent.ACTION_OPEN_DOCUMENT)
.addCategory(Intent.CATEGORY_OPENABLE)
.setType("application/vnd.android.package-archive")
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (Build.VERSION.SDK_INT >= 26) {
picker.putExtra("android.provider.extra.INITIAL_URI", Uri.parse(
"content://com.android.externalstorage.documents/document/primary%3ADownload"));
}
try {
context.startActivity(picker);
return true;
} catch (Throwable first) {
try {
Intent downloads = new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(downloads);
return true;
} catch (Throwable second) {
Log.w(TAG, "No Downloads UI available", second);
return false;
}
}
}
/** /**
* What {@link #install} did. The PackageInstaller is the authority for signing-certificate * What {@link #install} did. The PackageInstaller is the authority for signing-certificate
* compatibility, matching the proven DriveHub_Dort flow on this head unit. * compatibility, matching the proven DriveHub_Dort flow on this head unit.
@@ -117,25 +117,8 @@ final class UpdateHook {
if (apk == null) return "İndirme veya SHA-256 doğrulaması başarısız (" if (apk == null) return "İndirme veya SHA-256 doğrulaması başarısız ("
+ update.versionName + ")"; + update.versionName + ")";
OtaUpdater.InstallResult result = OtaUpdater.install(app, apk); if (!OtaUpdater.openDownloads(app))
// FileProvider's interactive installer opens asynchronously and still needs this file. return "APK Downloads'a indirildi; dosya yöneticisi açılamadı";
// Other outcomes have either streamed the bytes already or rejected the archive. return update.versionName + ".apk Downloads'a indirildi — dosyaya dokunup kurun";
if (result != OtaUpdater.InstallResult.INSTALL_UI_STARTED && !apk.delete()) {
Log.w(TAG, "Could not remove cached OTA APK");
}
switch (result) {
case SESSION_STARTED:
// Deliberately not "Güncellendi": committing a session is not installing. The
// platform may still want the driver to confirm, and either way the verdict
// arrives at OtaInstallResultReceiver, not here.
return "Kuruluyor: " + update.versionName + " — ekrandaki onayı bekleyin";
case INSTALL_UI_STARTED:
return "Kurulum ekranı açıldı: " + update.versionName;
case UNREADABLE_ARCHIVE:
return "Kurulum reddedildi: APK okunamadı";
default:
return "Kurulum başlatılamadı (" + update.versionName + ") — Log sayfasına bakın";
}
} }
} }