Java tutorial
/* * Copyright (c) 2015 Matthieu Harl * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package fr.shywim.antoinedaniel.sync; import android.content.ContentValues; import android.content.Context; import android.net.Uri; import com.crashlytics.android.Crashlytics; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.games.Games; import com.google.gson.Gson; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import fr.shywim.antoinedaniel.provider.ProviderConstants; import fr.shywim.antoinedaniel.provider.ProviderContract; import fr.shywim.antoinedaniel.utils.LogUtils; public class AppState { private static final String TAG = LogUtils.makeLogTag(AppState.class); static final AppState INSTANCE = new AppState(); public boolean changed = false; final Object LOCK = new Object(); final String WIDGET_SOUNDS = "widgets_sounds"; final String FAVORITES_SOUNDS = "favorites_sounds"; final String BEST_SCORES = "best_scores"; final String TIMESTAMP = "timestamp"; final String FILE_NAME = "appstate"; public final Set<String> widgetSounds = new HashSet<>(); public final Set<String> favSounds = new HashSet<>(); public final Map<String, String> bestScores = new HashMap<>(); public static AppState getInstance() { return INSTANCE; } private AppState() { } /** * Save the AppState to a file. * * @param context a context. */ public void save(Context context) { if (changed) { File privDir = context.getFilesDir(); File appState = new File(privDir, FILE_NAME); try { byte[] bytes = getAsByteArray(); if (appState.exists() || (!appState.exists() && appState.createNewFile())) { BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(appState)); bos.write(bytes); bos.flush(); bos.close(); } } catch (IOException e) { e.printStackTrace(); } } } /** * Load the AppState and sync it with the DB and the cloud. * * @param bytes loaded bytes. * @param context a context. * @param apiClient connected GoogleApiClient to sync with cloud or null. */ void loadFromBytes(byte[] bytes, Context context, GoogleApiClient apiClient) { try { String jsonString = new String(bytes); JSONObject json = new JSONObject(jsonString); importFromJSON(json, context, apiClient); } catch (JSONException e) { e.printStackTrace(); Crashlytics.logException(e); } } /** * Load AppState from file. * * @param context a context. */ public void load(final Context context) { File privDir = context.getFilesDir(); final File appState = new File(privDir, FILE_NAME); new Thread(new Runnable() { @Override public void run() { try { if (appState.exists()) { BufferedInputStream bis = new BufferedInputStream(new FileInputStream(appState)); byte[] bytes = new byte[(int) appState.length()]; for (int i = 0, temp; (temp = bis.read()) != -1; i++) { bytes[i] = (byte) temp; } bis.close(); loadFromBytes(bytes, context, null); } } catch (IOException e) { e.printStackTrace(); } } }).start(); } /** * @return AppState as a byte array. */ byte[] getAsByteArray() { try { return bundleInJSON().toString().getBytes("UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); Crashlytics.logException(e); } return null; } /** * @return AppState as a JSONObject. */ JSONObject bundleInJSON() { Gson gson = new Gson(); JSONArray widS = null; JSONArray favS = null; JSONObject scor = null; try { widS = new JSONArray(gson.toJson(widgetSounds)); favS = new JSONArray(gson.toJson(favSounds)); scor = new JSONObject(gson.toJson(bestScores)); } catch (JSONException e) { e.printStackTrace(); Crashlytics.logException(e); } JSONObject main = new JSONObject(); try { main.put(WIDGET_SOUNDS, widS); main.put(FAVORITES_SOUNDS, favS); main.put(BEST_SCORES, scor); main.put(TIMESTAMP, System.currentTimeMillis()); } catch (JSONException e) { e.printStackTrace(); Crashlytics.logException(e); } return main; } /** * Load AppState from a JSONObject. * * @param data json to import. */ void importFromJSON(JSONObject data, Context context, GoogleApiClient apiClient) { Gson gson = new Gson(); try { ContentValues cv = new ContentValues(); Set<String> widgetSounds = gson.fromJson(data.getJSONArray(WIDGET_SOUNDS).toString(), this.widgetSounds.getClass()); for (String soundName : widgetSounds) { synchronized (LOCK) { this.widgetSounds.add(soundName); } Uri uri = Uri.withAppendedPath(ProviderConstants.SOUND_NAME_URI, soundName); cv.clear(); cv.put(ProviderContract.SoundEntry.COLUMN_WIDGET, 1); context.getContentResolver().update(uri, cv, null, null); } Set<String> favSounds = gson.fromJson(data.getJSONArray(FAVORITES_SOUNDS).toString(), this.favSounds.getClass()); for (String soundName : favSounds) { synchronized (LOCK) { this.favSounds.add(soundName); } Uri uri = Uri.withAppendedPath(ProviderConstants.SOUND_NAME_URI, soundName); cv.clear(); cv.put(ProviderContract.SoundEntry.COLUMN_FAVORITE, 1); context.getContentResolver().update(uri, cv, null, null); } Map<String, String> bestScores = gson.fromJson(data.getJSONObject(BEST_SCORES).toString(), this.bestScores.getClass()); for (Map.Entry<String, String> entry : bestScores.entrySet()) { long newLong = Long.parseLong(entry.getValue()); synchronized (LOCK) { if (this.bestScores.containsKey(entry.getKey()) && Long.parseLong(this.bestScores.get(entry.getKey())) <= newLong) this.bestScores.put(entry.getKey(), entry.getValue()); } if (apiClient != null) { Games.Leaderboards.submitScore(apiClient, entry.getKey(), newLong); } } } catch (JSONException e) { e.printStackTrace(); } } }