package yuku.alkitab.base.config; import android.support.v4.util.AtomicFile; import android.util.Log; import yuku.afw.storage.Preferences; import yuku.alkitab.base.App; import yuku.alkitab.base.model.MVersionPreset; import yuku.alkitab.base.storage.Prefkey; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; import java.util.Map; public class VersionConfig { public static final String TAG = VersionConfig.class.getSimpleName(); public List<MVersionPreset> presets; public Map<String, String> locale_display; private static VersionConfig instance; private VersionConfig() { } static class PresetJson { public String locale; public String shortName; public String longName; public String description; public String preset_name; public int modifyTime; public boolean hidden; } static class VersionConfigJson { public List<PresetJson> presets; public String download_url_format; public Map<String, String> locale_display; } public static VersionConfig get() { if (instance != null) { return instance; } final VersionConfig latest = loadLatest(); instance = latest; return latest; } private static VersionConfig loadLatest() { final File updatedFile = getUpdatedFile(); if (updatedFile.exists() && updatedFile.canRead() && updatedFile.length() > 0) { try { final AtomicFile file = new AtomicFile(updatedFile); final String json = new String(file.readFully(), "utf-8"); final VersionConfigJson obj = App.getDefaultGson().fromJson(json, VersionConfigJson.class); return convertConfig(obj); } catch (Exception e) { // failed to load updated file, fallback to embedded Preferences.setInt(Prefkey.version_config_current_modify_time, 0); Preferences.setInt(Prefkey.version_config_last_update_check, 0); // fallthrough } } try { final InputStreamReader reader = new InputStreamReader(App.context.getAssets().open("version_config.json"), "utf-8"); final VersionConfigJson obj = App.getDefaultGson().fromJson(reader, VersionConfigJson.class); reader.close(); return convertConfig(obj); } catch (IOException e) { throw new RuntimeException("error in loading embedded version config", e); } } private static File getUpdatedFile() { return new File(App.context.getFilesDir(), "version_config.json"); } /** * Modify time for the version available for download. * * @return 0 if preset_name not known, or no updates supported. */ public int getModifyTime(final String preset_name) { if (preset_name == null) return 0; for (final MVersionPreset preset : presets) { if (preset_name.equals(preset.preset_name)) { return preset.modifyTime; } } return 0; } public MVersionPreset getPreset(final String preset_name) { if (preset_name == null) return null; for (final MVersionPreset preset : presets) { if (preset_name.equals(preset.preset_name)) { return preset; } } return null; } /** * Does not do anything persistent. */ private static VersionConfig convertConfig(VersionConfigJson root) { final VersionConfig res = new VersionConfig(); final List<MVersionPreset> presets = new ArrayList<>(); int presetOrdering = 10; for (PresetJson presetJson : root.presets) { final MVersionPreset preset = new MVersionPreset(); preset.locale = presetJson.locale; preset.shortName = presetJson.shortName; preset.longName = presetJson.longName; preset.description = presetJson.description; preset.preset_name = presetJson.preset_name; preset.modifyTime = presetJson.modifyTime; preset.hidden = presetJson.hidden; preset.download_url = root.download_url_format.replace("$PRESET_NAME", presetJson.preset_name); preset.ordering = ++presetOrdering; presets.add(preset); } res.locale_display = root.locale_display; res.presets = presets; return res; } /** Checks if the given json is a valid version config file */ public static boolean isValid(final String json) { try { convertConfig(App.getDefaultGson().fromJson(json, VersionConfigJson.class)); return true; } catch (Exception e) { Log.d(TAG, "@@isValid not valid json file", e); return false; } } /** * Must be assumed that the given json is valid. * Pass the json to the {@link #isValid(String)} first. * * @return true when success */ public static boolean useLatest(final String json, final int modifyTime) { try { final AtomicFile file = new AtomicFile(getUpdatedFile()); final FileOutputStream fos = file.startWrite(); fos.write(json.getBytes("utf-8")); file.finishWrite(fos); } catch (IOException e) { Log.d(TAG, "Failed to write to update file", e); return false; } Preferences.setInt(Prefkey.version_config_current_modify_time, modifyTime); instance = loadLatest(); return true; } }