/**
* Copyright 2010 Eric Taix Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and limitations under the
* License.
*/
package com.bigpupdev.synodroid;
import java.util.ArrayList;
import java.util.List;
import com.bigpupdev.synodroid.server.SynoServer;
import com.bigpupdev.synodroid.server.SynoServerConnection;
import com.bigpupdev.synodroid.protocol.ResponseHandler;
import com.bigpupdev.synodroid.ui.DetailFiles;
import com.bigpupdev.synodroid.ui.DetailMain;
import com.bigpupdev.synodroid.ui.DownloadFragment;
import com.bigpupdev.synodroid.ui.SearchFragment;
import com.bigpupdev.synodroid.ui.SynodroidFragment;
import com.bigpupdev.synodroid.utils.Utils;
import com.bigpupdev.synodroid.R;
import com.bigpupdev.synodroid.action.DeleteMultipleTaskAction;
import com.bigpupdev.synodroid.action.DeleteTaskAction;
import com.bigpupdev.synodroid.action.SynoAction;
import de.keyboardsurfer.android.widget.crouton.Style;
import de.keyboardsurfer.android.widget.crouton.Style.Builder;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Application;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Message;
import android.util.Log;
import android.view.ViewGroup.LayoutParams;
/**
* The application (single instance) which implements utility methods to access to the current server
*
* @author Eric Taix (eric.taix at gmail.com)
*/
public class Synodroid extends Application {
private static final String PREFERENCE_DEBUG = "debug_cat";
private static final String PREFERENCE_DEBUG_LOG = "debug_cat.debug_logging";
public static final String DS_TAG = "Synodroid";
public boolean DEBUG;
// The current server
private SynoServer currentServer = null;
private String curBrowserUrl = null;
public static final Style CROUTON_ERROR;
public static final Style CROUTON_ALERT;
public static final Style CROUTON_CONFIRM;
public static final Style CROUTON_INFO;
public static final int holoRedLight = 0xddff4444;
public static final int holoGreenLight = 0xdd99cc00;
public static final int holoBlueLight = 0xdd33b5e5;
static {
CROUTON_ERROR = new Builder().setDuration(-1).setBackgroundColorValue(holoRedLight).setHeight(LayoutParams.WRAP_CONTENT).build();
CROUTON_ALERT = new Builder().setDuration(1300).setBackgroundColorValue(holoRedLight).setHeight(LayoutParams.WRAP_CONTENT).build();
CROUTON_CONFIRM = new Builder().setDuration(1300).setBackgroundColorValue(holoGreenLight).setHeight(LayoutParams.WRAP_CONTENT).build();
CROUTON_INFO = new Builder().setDuration(1300).setBackgroundColorValue(holoBlueLight).setHeight(LayoutParams.WRAP_CONTENT).build();
}
/*
* (non-Javadoc)
*
* @see android.app.Application#onCreate()
*/
@Override
public void onCreate() {
super.onCreate();
SharedPreferences preferences = getSharedPreferences(PREFERENCE_DEBUG, Activity.MODE_PRIVATE);
DEBUG = preferences.getBoolean(PREFERENCE_DEBUG_LOG, false);
}
/*
* (non-Javadoc)
*
* @see android.app.Application#onTerminate()
*/
@Override
public void onTerminate() {
super.onTerminate();
}
public void setBrowserUrl(String url){
curBrowserUrl = url;
}
public String getBrowserUrl(){
return curBrowserUrl;
}
public void enableDebugLog(){
DEBUG = true;
if (currentServer != null) currentServer.setDebugLvl(DEBUG);
}
public void disableDebugLog(){
DEBUG = false;
if (currentServer != null) currentServer.setDebugLvl(DEBUG);
}
public boolean isNetworkAvailable() {
ConnectivityManager connectivityManager
= (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
return activeNetworkInfo != null;
}
/**
* Set the current server. An attempt to connect to the server is only done if this is different server
*
* @param activityP
* @param serverP
*/
public synchronized void connectServer(SynodroidFragment activityP, SynoServer serverP, List<SynoAction> actionQueueP, boolean automated) {
connectServer(activityP, serverP, actionQueueP, automated, null);
}
public boolean shouldUsePublicConnection(){
boolean pub = true;
// Determine the current network access
WifiManager wifiMgr = (WifiManager) getSystemService(Context.WIFI_SERVICE);
boolean wifiOn = wifiMgr.isWifiEnabled();
if (DEBUG){
if (wifiOn){
Log.v(Synodroid.DS_TAG, "Synodroid: Wifi is: ENABLED.");
}
else{
Log.v(Synodroid.DS_TAG, "Synodroid: Wifi is: DISABLED.");
}
}
final WifiInfo currentWifi = wifiMgr.getConnectionInfo();
final boolean wifiConnected = (wifiOn && currentWifi.getNetworkId() != -1);
if (DEBUG){
if (wifiConnected){
Log.v(Synodroid.DS_TAG, "Synodroid: Wifi is: CONNECTED.");
}
else{
Log.v(Synodroid.DS_TAG, "Synodroid: Wifi is: DISCONNECTED.");
}
}
// If we are connected to a WIFI network, verify if SSID match
String cur_ssid = Utils.validateSSID(currentWifi.getSSID());
if (wifiConnected && cur_ssid != null) {
if (DEBUG) Log.v(Synodroid.DS_TAG, "Synodroid: Wifi current SSID is: '" + cur_ssid+"'");
SynoServerConnection sc = currentServer.getLocalConnection();
if (sc != null) {
List<String> ssids = sc.wifiSSID;
if (ssids != null) {
if (DEBUG) Log.v(Synodroid.DS_TAG, "Synodroid: Local connection has an SSID list! Checking to find the right SSID...");
for (String ssid : ssids) {
ssid = Utils.validateSSID(ssid);
if (DEBUG) Log.v(Synodroid.DS_TAG, "Synodroid: Comparing '"+ssid+"' with '" + cur_ssid+"' ...");
if (cur_ssid.equals(ssid)) {
pub = false;
if (DEBUG) Log.v(Synodroid.DS_TAG, "Synodroid: SSIDs are equal! Connecting using local connection...");
break;
}
}
}
}
}
return pub;
}
public synchronized void connectServer(SynodroidFragment activityP, SynoServer serverP, List<SynoAction> actionQueueP, boolean automated, String otp) {
// if (currentServer == null || !currentServer.isAlive() || !currentServer.equals(serverP)) {
// First disconnect the old server
if (currentServer != null && !automated) {
currentServer.disconnect();
}
// Then connect the new one
currentServer = serverP;
currentServer.connect(activityP, actionQueueP, shouldUsePublicConnection(), otp);
// }
}
/**
* Get the current server
*
* @return currentServer
*/
public SynoServer getServer() {
return currentServer;
}
/**
* Bind an activity to the current server
*
* @param handlerP
*/
public boolean bindResponseHandler(ResponseHandler handlerP) {
if (currentServer == null) {
return false;
} else {
currentServer.bindResponseHandler(handlerP);
return true;
}
}
/**
* Change the recurrent action
*
* @param actionP
*/
public void setRecurrentAction(ResponseHandler handlerP, SynoAction actionP) {
if (currentServer != null) {
currentServer.setRecurrentAction(handlerP, actionP);
}
}
/**
* Force a refresh
*/
public void forceRefresh() {
if (currentServer != null) {
currentServer.forceRefresh();
}
}
/**
* Delay a refresh for 2 seconds
*/
public void delayedRefresh() {
if (currentServer != null) {
currentServer.delayedRefresh();
}
}
/**
* Pause the current server if exist
*/
public void pauseServer() {
if (currentServer != null) {
currentServer.pause();
}
}
/**
* Resume the current server if exist
*/
public void resumeServer() {
if (currentServer != null) {
currentServer.resume();
}
}
/**
* Execute an action and connect to the server or display the connection dialog if needed
*
* @param activityP
* @param actionP
* @param forceRefreshP
*/
public void executeAction(final DetailMain fragmentP, final SynoAction actionP, final boolean forceRefreshP) {
if (currentServer != null) {
// First verify if it is a DeleteTaskAction and if the task is not finished
if ((actionP instanceof DeleteTaskAction) && actionP.requireConfirm()) {
Activity a = fragmentP.getActivity();
Dialog d = new AlertDialog.Builder(a).setTitle(actionP.getTask().fileName).setMessage(R.string.dialog_message_confirm).setNegativeButton(android.R.string.no, null).setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
currentServer.setRecurrentAction(fragmentP, null);
currentServer.executeAsynchronousAction(fragmentP, actionP, forceRefreshP);
fragmentP.finish();
}
}).create();
// d.setOwnerActivity(this); // why can't the builder do this?
d.show();
}
else if (actionP instanceof DeleteTaskAction) {
currentServer.setRecurrentAction(fragmentP, null);
currentServer.executeAsynchronousAction(fragmentP, actionP, forceRefreshP);
fragmentP.finish();
}
// Ok no problem do it
else {
currentServer.executeAsynchronousAction(fragmentP, actionP, forceRefreshP);
}
}
// If an action have to be executed but with no current connection
else {
ArrayList<SynoAction> actionQueue = new ArrayList<SynoAction>();
actionQueue.add(actionP);
fragmentP.setAlreadyCanceled(false);
fragmentP.showDialogToConnect(true, actionQueue, true);
}
}
/**
* Execute an action and connect to the server or display the connection dialog if needed
*
* @param activityP
* @param actionP
* @param forceRefreshP
*/
public void executeAction(final SearchFragment fragmentP, final SynoAction actionP, final boolean forceRefreshP) {
if (currentServer != null) {
// First verify if it is a DeleteTaskAction and if the task is not finished
currentServer.executeAsynchronousAction(fragmentP, actionP, forceRefreshP);
}
// If an action have to be executed but with no current connection
else {
ArrayList<SynoAction> actionQueue = new ArrayList<SynoAction>();
actionQueue.add(actionP);
fragmentP.setAlreadyCanceled(false);
fragmentP.showDialogToConnect(true, actionQueue, true);
}
}
/**
* Execute an action and connect to the server or display the connection dialog if needed
*
* @param activityP
* @param actionP
* @param forceRefreshP
*/
public void executeAction(final DetailFiles fragmentP, final SynoAction actionP, final boolean forceRefreshP) {
if (currentServer != null) {
// First verify if it is a DeleteTaskAction and if the task is not finished
currentServer.executeAsynchronousAction(fragmentP, actionP, forceRefreshP);
}
// If an action have to be executed but with no current connection
else {
ArrayList<SynoAction> actionQueue = new ArrayList<SynoAction>();
actionQueue.add(actionP);
fragmentP.setAlreadyCanceled(false);
fragmentP.showDialogToConnect(true, actionQueue, true);
}
}
/**
* Execute an action and connect to the server or display the connection dialog if needed
*
* @param activityP
* @param actionP
* @param forceRefreshP
*/
public void executeAction(final DownloadFragment fragmentP, final SynoAction actionP, final boolean forceRefreshP) {
if (currentServer != null && currentServer.isConnected()) {
// First verify if it is a DeleteTaskAction and if the task is not finished
if ((actionP instanceof DeleteTaskAction) && actionP.requireConfirm()) {
Activity a = fragmentP.getActivity();
Dialog d = new AlertDialog.Builder(a).setTitle(actionP.getTask().fileName).setMessage(R.string.dialog_message_confirm).setNegativeButton(android.R.string.no, null).setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
currentServer.executeAsynchronousAction(fragmentP, actionP, forceRefreshP);
}
}).create();
// d.setOwnerActivity(this); // why can't the builder do this?
d.show();
}
else if (actionP instanceof DeleteMultipleTaskAction && actionP.requireConfirm()) {
Activity a = fragmentP.getActivity();
Dialog d = new AlertDialog.Builder(a).setTitle(R.string.delete_multiple).setMessage(R.string.dialog_multiple_confirm).setNegativeButton(android.R.string.no, null).setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
currentServer.executeAsynchronousAction(fragmentP, actionP, forceRefreshP);
}
}).create();
// d.setOwnerActivity(this); // why can't the builder do this?
d.show();
}
// Ok no problem do it
else {
currentServer.executeAsynchronousAction(fragmentP, actionP, forceRefreshP);
}
}
// If an action have to be executed but with no current connection
else {
ArrayList<SynoAction> actionQueue = new ArrayList<SynoAction>();
actionQueue.add(actionP);
fragmentP.setAlreadyCanceled(false);
fragmentP.showDialogToConnect(true, actionQueue, true);
}
}
/**
* Change the sort
*
* @param sorAttrP
* @param ascendingP
*/
public void setServerSort(String sorAttrP, boolean ascendingP) {
if (currentServer != null) {
currentServer.setSortAttribute(sorAttrP);
currentServer.setAscending(ascendingP);
currentServer.forceRefresh();
}
}
public String getServerSort(){
return currentServer.getSortAttribute();
}
/**
* Execute an asynchronous action if the server is currently connected
*
* @param handlerP
* @param actionP
* @param forceRefreshP
* @param showToastP
*/
public void executeAsynchronousAction(ResponseHandler handlerP, SynoAction actionP, final boolean forceRefreshP, final boolean showToastP) {
if (currentServer != null && currentServer.isConnected()) {
currentServer.executeAsynchronousAction(handlerP, actionP, forceRefreshP, showToastP);
}
else{
ArrayList<SynoAction> actionQueue = new ArrayList<SynoAction>();
actionQueue.add(actionP);
fireMessage(handlerP, ResponseHandler.MSG_CONNECT_WITH_ACTION, actionQueue);
}
}
/**
* Execute an asynchronous action if the server is currently connected
*
* @param handlerP
* @param actionP
* @param forceRefreshP
*/
public void executeAsynchronousAction(ResponseHandler handlerP, SynoAction actionP, final boolean forceRefreshP) {
if (currentServer != null && currentServer.isConnected()) {
currentServer.executeAsynchronousAction(handlerP, actionP, forceRefreshP);
}
else{
ArrayList<SynoAction> actionQueue = new ArrayList<SynoAction>();
actionQueue.add(actionP);
fireMessage(handlerP, ResponseHandler.MSG_CONNECT_WITH_ACTION, actionQueue);
}
}
/**
* Send a message
*/
public void fireMessage(ResponseHandler handlerP, int msgP) {
fireMessage(handlerP, msgP, null);
}
/**
* Send a message
*/
public void fireMessage(ResponseHandler handlerP, int msgP, Object objP) {
// Send the connecting message
Message msg = new Message();
msg.what = msgP;
msg.obj = objP;
handlerP.handleReponse(msg);
}
}