fr.shywim.antoinedaniel.sync.AppState.java Source code

Java tutorial

Introduction

Here is the source code for fr.shywim.antoinedaniel.sync.AppState.java

Source

/*
 * 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();
        }
    }
}