/* * Author: Balch * Created: 9/4/14 12:26 AM * * This file is part of MockTrade. * * MockTrade is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * MockTrade is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with MockTrade. If not, see <http://www.gnu.org/licenses/>. * * Copyright (C) 2014 */ package com.balch.mocktrade; import android.app.Application; import android.content.Context; import android.content.res.Configuration; import android.os.AsyncTask; import android.os.Environment; import android.os.StrictMode; import android.util.Log; import com.android.volley.DefaultRetryPolicy; import com.android.volley.Request; import com.android.volley.RequestQueue; import com.android.volley.toolbox.Volley; import com.balch.android.app.framework.sql.SqlConnection; import com.balch.mocktrade.finance.FinanceModel; import com.balch.mocktrade.finance.GoogleFinanceModel; import com.balch.mocktrade.portfolio.PortfolioModel; import com.balch.mocktrade.portfolio.PortfolioSqliteModel; import com.balch.mocktrade.services.WearSyncService; import com.balch.mocktrade.settings.Settings; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FilenameFilter; import java.io.IOException; import java.nio.channels.FileChannel; import java.util.Arrays; import java.util.Comparator; public class TradeApplication extends Application implements TradeModelProvider, ViewProvider { private static final String TAG = TradeApplication.class.getSimpleName(); private static final int REQUEST_TIMEOUT_SECS = 30; private static final DefaultRetryPolicy DEFAULT_RETRY_POlICY = new DefaultRetryPolicy( REQUEST_TIMEOUT_SECS * 1000, 0, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT); public static final String DATABASE_NAME = "mocktrade.db"; private static final int DATABASE_VERSION = 5; private static final String DATABASE_CREATES_SCRIPT = "sql/create.sql"; private static final String DATABASE_UPDATE_SCRIPT_FORMAT = "sql/upgrade_%d.sql"; private static final String DAILY_BACKUP_DATABASE_NAME = "daily_backup"; private volatile SqlConnection sqlConnection; private volatile RequestQueue requestQueue; private volatile Settings settings; private volatile VolleyNetworkRequest networkRequest; @Override public void onCreate() { super.onCreate(); if (BuildConfig.DEBUG) { StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() .detectDiskReads() .detectDiskWrites() .detectNetwork() .penaltyLog() .build()); StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() .detectLeakedSqlLiteObjects() .detectLeakedClosableObjects() .penaltyLog() .build()); } startService(WearSyncService.getIntent(this, true, true, true, false)); new StartAlarmsTask(this).execute(); } private static class StartAlarmsTask extends AsyncTask<Void, Void, Void> { private final TradeModelProvider modelProvider; private StartAlarmsTask(TradeModelProvider modelProvider) { this.modelProvider = modelProvider; } protected Void doInBackground(Void... urls) { FinanceModel financeModel = new GoogleFinanceModel(modelProvider.getContext(), modelProvider.getNetworkRequestProvider(), modelProvider.getSettings()); financeModel.setQuoteServiceAlarm(); PortfolioModel portfolioModel = new PortfolioSqliteModel(modelProvider.getContext(), modelProvider.getSqlConnection(), modelProvider.getNetworkRequestProvider(), modelProvider.getSettings()); portfolioModel.scheduleOrderServiceAlarmIfNeeded(); return null; } } @Override public Context getContext() { return this; } @Override public SqlConnection getSqlConnection() { // double check lock pattern if (sqlConnection == null) { synchronized (this) { if (sqlConnection == null) { sqlConnection = new SqlConnection(this, DATABASE_NAME, DATABASE_VERSION, DATABASE_CREATES_SCRIPT, DATABASE_UPDATE_SCRIPT_FORMAT); } } } return sqlConnection; } @Override public NetworkRequestProvider getNetworkRequestProvider() { // double check lock pattern if (this.networkRequest == null) { synchronized (this) { if (this.networkRequest == null) { this.requestQueue = Volley.newRequestQueue(this); this.networkRequest = new VolleyNetworkRequest(this.requestQueue); } } } return this.networkRequest; } @Override public Settings getSettings() { // double check lock pattern if (settings == null) { synchronized (this) { if (settings == null) { settings = new Settings(this); } } } return settings; } @Override public boolean isTablet(Context context) { return context.getResources().getBoolean(R.bool.isTablet); } @Override public boolean isLandscape(Context context) { return (context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE); } public static boolean backupDatabase(Context context, boolean isDaily) { boolean success = false; String backupDBPathPrefix; if (isDaily) { backupDBPathPrefix = DAILY_BACKUP_DATABASE_NAME; if (BuildConfig.DEBUG) { backupDBPathPrefix += "_debug"; } } else { backupDBPathPrefix = String.valueOf(System.currentTimeMillis()); } String backupDBPath = backupDBPathPrefix + "_" + DATABASE_NAME; FileChannel src = null; FileChannel dst = null; try { File sd = Environment.getExternalStorageDirectory(); if (sd.canWrite()) { File dbFile = context.getDatabasePath(TradeApplication.DATABASE_NAME); File backupDBFile = new File(sd, backupDBPath); if (dbFile.exists()) { src = new FileInputStream(dbFile).getChannel(); dst = new FileOutputStream(backupDBFile).getChannel(); dst.transferFrom(src, 0, src.size()); success = true; } } } catch (Exception e) { Log.e(TAG, "Error backing up to Database", e); } finally { if (src != null) { try { src.close(); } catch (IOException ignored) { } } if (dst != null) try { dst.close(); } catch (IOException ignored) { } } return success; } public static boolean restoreDatabase(Context context) { boolean success = false; FileChannel src = null; FileChannel dst = null; try { File sd = Environment.getExternalStorageDirectory(); if (sd.canWrite()) { File dbFile = context.getDatabasePath(TradeApplication.DATABASE_NAME); File[] backups = sd.listFiles(new FilenameFilter() { public boolean accept(File dir, String name) { return name.startsWith("1") && name.endsWith("_" + TradeApplication.DATABASE_NAME); } }); if (backups != null && backups.length > 1) { Arrays.sort(backups, new Comparator<File>() { @Override public int compare(File object1, File object2) { return object1.getName().compareTo(object2.getName()); } }); } if (backups != null) { src = new FileInputStream(backups[backups.length - 1]).getChannel(); dst = new FileOutputStream(dbFile).getChannel(); dst.transferFrom(src, 0, src.size()); success = true; } } } catch (Exception e) { Log.e(TAG, "Error restoring Database", e); } finally { if (src != null) { try { src.close(); } catch (IOException ignored) { } } if (dst != null) try { dst.close(); } catch (IOException ignored) { } } return success; } static class VolleyNetworkRequest implements NetworkRequestProvider { private final RequestQueue requestQueue; VolleyNetworkRequest(RequestQueue requestQueue) { this.requestQueue = requestQueue; } @Override public <T> Request<T> addRequest(Request<T> request) { return addRequest(request, false); } @Override public <T> Request<T> addRequest(Request<T> request, boolean customRetryPolicy) { if (!customRetryPolicy) { request.setRetryPolicy(DEFAULT_RETRY_POlICY); } return this.requestQueue.add(request); } } }