Loading app/src/main/java/org/lineageos/updater/UpdateImporter.java +80 −7 Original line number Diff line number Diff line Loading @@ -18,9 +18,13 @@ package org.lineageos.updater; import android.annotation.SuppressLint; import android.app.Activity; import android.content.ContentResolver; import android.content.Intent; import android.database.Cursor; import android.net.Uri; import android.os.Build; import android.os.ParcelFileDescriptor; import android.provider.OpenableColumns; import android.util.Log; import org.lineageos.updater.controller.UpdaterController; Loading @@ -38,6 +42,9 @@ import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.text.DateFormat; import java.util.Enumeration; import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; Loading @@ -48,11 +55,13 @@ public class UpdateImporter { private static final String FILE_NAME = "localUpdate.zip"; private static final String METADATA_PATH = "META-INF/com/android/metadata"; private static final String METADATA_TIMESTAMP_KEY = "post-timestamp="; private static final String METADATA_ANDROID_SDK_KEY = "post-sdk-level="; private final Activity activity; private final Callbacks callbacks; private Thread workingThread; private String filename; public UpdateImporter(Activity activity, Callbacks callbacks) { this.activity = activity; Loading Loading @@ -89,6 +98,7 @@ public class UpdateImporter { File importedFile = null; try { importedFile = importFile(uri); filename = getFileNameFromUri(uri); verifyPackage(importedFile); final Update update = buildLocalUpdate(importedFile); Loading @@ -108,6 +118,29 @@ public class UpdateImporter { return true; } public String getFileNameFromUri(Uri uri) { String fileName = null; if (Objects.equals(uri.getScheme(), "content")) { ContentResolver contentResolver = activity.getContentResolver(); Cursor cursor = contentResolver.query(uri, null, null, null, null); if (cursor != null) { try { if (cursor.moveToFirst()) { int displayNameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); if (displayNameIndex != -1) { fileName = cursor.getString(displayNameIndex); } } } finally { cursor.close(); } } } else if (Objects.equals(uri.getScheme(), "file")) { fileName = uri.getLastPathSegment(); } return fileName; } @SuppressLint("SetWorldReadable") @SuppressWarnings("ResultOfMethodCallIgnored") private File importFile(Uri uri) throws IOException { Loading Loading @@ -145,8 +178,18 @@ public class UpdateImporter { final long timeStamp = getTimeStamp(file); final String buildDate = StringGenerator.getDateLocalizedUTC( activity, DateFormat.MEDIUM, timeStamp); final String name = activity.getString(R.string.local_update_name); String name = activity.getString(R.string.local_update_name); final String androidVersion = getAndroidVersion(file); final Update update = new Update(); if (filename != null) { Pattern pattern = Pattern.compile("-(\\d+\\.\\d+(\\.\\d+)?)"); Matcher matcher = pattern.matcher(filename); if (matcher.find()) { name = matcher.group(1); } } update.setAvailableOnline(false); update.setName(name); update.setFile(file); Loading @@ -156,6 +199,8 @@ public class UpdateImporter { update.setStatus(UpdateStatus.VERIFIED); update.setPersistentStatus(UpdateStatus.Persistent.VERIFIED); update.setVersion(String.format("%s (%s)", name, buildDate)); update.setAndroidVersion(androidVersion); update.setDisplayVersion(name); return update; } Loading @@ -179,25 +224,53 @@ public class UpdateImporter { } private long getTimeStamp(File file) { String timeStamp = getFromMetadata(file, METADATA_TIMESTAMP_KEY); if (timeStamp != null) { return Long.parseLong(timeStamp); } return System.currentTimeMillis(); } private String getAndroidVersion(File file) { String sdkInt = getFromMetadata(file, METADATA_ANDROID_SDK_KEY); if (sdkInt != null) { return sdkToVersion(Integer.parseInt(sdkInt)); } return Build.VERSION.RELEASE; } private static String sdkToVersion(int sdkInt) { return switch (sdkInt) { case Build.VERSION_CODES.Q -> "10"; case Build.VERSION_CODES.R -> "11"; case Build.VERSION_CODES.S, Build.VERSION_CODES.S_V2 -> "12"; case Build.VERSION_CODES.TIRAMISU -> "13"; case Build.VERSION_CODES.UPSIDE_DOWN_CAKE -> "14"; case Build.VERSION_CODES.VANILLA_ICE_CREAM -> "15"; case Build.VERSION_CODES.BAKLAVA -> "16"; default -> Build.VERSION.RELEASE; }; } private String getFromMetadata(File file, String key) { try { final String metadataContent = readZippedFile(file, METADATA_PATH); final String[] lines = metadataContent.split("\n"); for (String line : lines) { if (!line.startsWith(METADATA_TIMESTAMP_KEY)) { if (!line.startsWith(key)) { continue; } final String timeStampStr = line.replace(METADATA_TIMESTAMP_KEY, ""); return Long.parseLong(timeStampStr); return line.replace(key, ""); } } catch (IOException e) { Log.e(TAG, "Failed to read date from local update zip package", e); } catch (NumberFormatException e) { Log.e(TAG, "Failed to parse timestamp number from zip metadata file", e); Log.e(TAG, "Failed to parse from zip metadata file", e); } Log.e(TAG, "Couldn't find timestamp in zip file, falling back to $now"); return System.currentTimeMillis(); Log.e(TAG, "Couldn't find metadata in zip file, falling back to 0"); return null; } private String readZippedFile(File file, String path) throws IOException { Loading Loading
app/src/main/java/org/lineageos/updater/UpdateImporter.java +80 −7 Original line number Diff line number Diff line Loading @@ -18,9 +18,13 @@ package org.lineageos.updater; import android.annotation.SuppressLint; import android.app.Activity; import android.content.ContentResolver; import android.content.Intent; import android.database.Cursor; import android.net.Uri; import android.os.Build; import android.os.ParcelFileDescriptor; import android.provider.OpenableColumns; import android.util.Log; import org.lineageos.updater.controller.UpdaterController; Loading @@ -38,6 +42,9 @@ import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.text.DateFormat; import java.util.Enumeration; import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; Loading @@ -48,11 +55,13 @@ public class UpdateImporter { private static final String FILE_NAME = "localUpdate.zip"; private static final String METADATA_PATH = "META-INF/com/android/metadata"; private static final String METADATA_TIMESTAMP_KEY = "post-timestamp="; private static final String METADATA_ANDROID_SDK_KEY = "post-sdk-level="; private final Activity activity; private final Callbacks callbacks; private Thread workingThread; private String filename; public UpdateImporter(Activity activity, Callbacks callbacks) { this.activity = activity; Loading Loading @@ -89,6 +98,7 @@ public class UpdateImporter { File importedFile = null; try { importedFile = importFile(uri); filename = getFileNameFromUri(uri); verifyPackage(importedFile); final Update update = buildLocalUpdate(importedFile); Loading @@ -108,6 +118,29 @@ public class UpdateImporter { return true; } public String getFileNameFromUri(Uri uri) { String fileName = null; if (Objects.equals(uri.getScheme(), "content")) { ContentResolver contentResolver = activity.getContentResolver(); Cursor cursor = contentResolver.query(uri, null, null, null, null); if (cursor != null) { try { if (cursor.moveToFirst()) { int displayNameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); if (displayNameIndex != -1) { fileName = cursor.getString(displayNameIndex); } } } finally { cursor.close(); } } } else if (Objects.equals(uri.getScheme(), "file")) { fileName = uri.getLastPathSegment(); } return fileName; } @SuppressLint("SetWorldReadable") @SuppressWarnings("ResultOfMethodCallIgnored") private File importFile(Uri uri) throws IOException { Loading Loading @@ -145,8 +178,18 @@ public class UpdateImporter { final long timeStamp = getTimeStamp(file); final String buildDate = StringGenerator.getDateLocalizedUTC( activity, DateFormat.MEDIUM, timeStamp); final String name = activity.getString(R.string.local_update_name); String name = activity.getString(R.string.local_update_name); final String androidVersion = getAndroidVersion(file); final Update update = new Update(); if (filename != null) { Pattern pattern = Pattern.compile("-(\\d+\\.\\d+(\\.\\d+)?)"); Matcher matcher = pattern.matcher(filename); if (matcher.find()) { name = matcher.group(1); } } update.setAvailableOnline(false); update.setName(name); update.setFile(file); Loading @@ -156,6 +199,8 @@ public class UpdateImporter { update.setStatus(UpdateStatus.VERIFIED); update.setPersistentStatus(UpdateStatus.Persistent.VERIFIED); update.setVersion(String.format("%s (%s)", name, buildDate)); update.setAndroidVersion(androidVersion); update.setDisplayVersion(name); return update; } Loading @@ -179,25 +224,53 @@ public class UpdateImporter { } private long getTimeStamp(File file) { String timeStamp = getFromMetadata(file, METADATA_TIMESTAMP_KEY); if (timeStamp != null) { return Long.parseLong(timeStamp); } return System.currentTimeMillis(); } private String getAndroidVersion(File file) { String sdkInt = getFromMetadata(file, METADATA_ANDROID_SDK_KEY); if (sdkInt != null) { return sdkToVersion(Integer.parseInt(sdkInt)); } return Build.VERSION.RELEASE; } private static String sdkToVersion(int sdkInt) { return switch (sdkInt) { case Build.VERSION_CODES.Q -> "10"; case Build.VERSION_CODES.R -> "11"; case Build.VERSION_CODES.S, Build.VERSION_CODES.S_V2 -> "12"; case Build.VERSION_CODES.TIRAMISU -> "13"; case Build.VERSION_CODES.UPSIDE_DOWN_CAKE -> "14"; case Build.VERSION_CODES.VANILLA_ICE_CREAM -> "15"; case Build.VERSION_CODES.BAKLAVA -> "16"; default -> Build.VERSION.RELEASE; }; } private String getFromMetadata(File file, String key) { try { final String metadataContent = readZippedFile(file, METADATA_PATH); final String[] lines = metadataContent.split("\n"); for (String line : lines) { if (!line.startsWith(METADATA_TIMESTAMP_KEY)) { if (!line.startsWith(key)) { continue; } final String timeStampStr = line.replace(METADATA_TIMESTAMP_KEY, ""); return Long.parseLong(timeStampStr); return line.replace(key, ""); } } catch (IOException e) { Log.e(TAG, "Failed to read date from local update zip package", e); } catch (NumberFormatException e) { Log.e(TAG, "Failed to parse timestamp number from zip metadata file", e); Log.e(TAG, "Failed to parse from zip metadata file", e); } Log.e(TAG, "Couldn't find timestamp in zip file, falling back to $now"); return System.currentTimeMillis(); Log.e(TAG, "Couldn't find metadata in zip file, falling back to 0"); return null; } private String readZippedFile(File file, String path) throws IOException { Loading