/*
* Copyright 2011 Google Inc.
*
* 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.ui;
import java.util.ArrayList;
import java.util.List;
import com.bigpupdev.synodroid.R;
import com.bigpupdev.synodroid.Synodroid;
import com.bigpupdev.synodroid.action.SynoAction;
import com.bigpupdev.synodroid.adapter.SlidingMenuAdapter;
import com.bigpupdev.synodroid.preference.PreferenceFacade;
import com.bigpupdev.synodroid.server.SynoServer;
import com.bigpupdev.synodroid.utils.ActionModeHelper;
import com.bigpupdev.synodroid.utils.ActivityHelper;
import com.bigpupdev.synodroid.utils.EulaHelper;
import com.bigpupdev.synodroid.utils.SlidingMenuItem;
import com.slidingmenu.lib.SlidingMenu;
import de.keyboardsurfer.android.widget.crouton.Crouton;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.DialogInterface.OnDismissListener;
import android.content.res.Configuration;
import android.net.Uri;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.WindowManager.BadTokenException;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;
/**
* A base activity that defers common functionality across app activities to an
* {@link ActivityHelper}. This class shouldn't be used directly; instead, activities should
* inherit from {@link BaseSinglePaneActivity} or {@link BaseMultiPaneActivity}.
*/
public abstract class BaseActivity extends FragmentActivity {
private static final String PREFERENCE_AUTO = "auto";
private static final String PREFERENCE_AUTO_CREATENOW = "auto.createnow";
private static final String PREFERENCE_GENERAL = "general_cat";
private static final String PREFERENCE_AUTO_DSM = "general_cat.auto_detect_DSM";
private static final String PREFERENCE_DEF_SRV = "servers_cat.default_srv";
private static final String PREFERENCE_SERVER = "servers_cat";
final ActivityHelper mActivityHelper = ActivityHelper.createInstance(this);
final ActionModeHelper mActionModeHelper = ActionModeHelper.createInstance();
private static final int SMNU_DL = 0;
private static final int SMNU_BR = 1;
private static final int SMNU_FI = 2;
private static final int SMNU_RS = 3;
private static final int SMNU_SE = 4;
private static final int SMNU_HP = 5;
private static final int SMNU_AB = 6;
private static final int SMNU_SET = 7;
public static final int NO_SERVER_DIALOG_ID = 2;
public static final int OTP_REQUEST_DIALOG_ID = 4;
// Flag to tell app that the connect dialog is opened
private boolean connectDialogOpened = false;
private boolean alreadyCanceled = false;
protected SlidingMenu menu = null;
private SlidingMenuItem menuListSelectedItem = null;
public SlidingMenu getSlidingMenu(){
return menu;
};
public boolean getAlreadyCanceled(){
return alreadyCanceled;
}
public void setAlreadyCanceled(boolean value){
alreadyCanceled = value;
}
public void updateActionBarTitleOCL(android.view.View.OnClickListener ocl){
ActivityHelper ah = getActivityHelper();
if (ah != null) ah.setTitleOnClickListener(ocl);
}
/**
* Show the preference activity
*/
public void showSearchActivity(boolean clear) {
Intent next = new Intent();
if (clear) next.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
next.setClass(this, SearchActivity.class);
next.putExtra("start_search", true);
startActivity(next);
}
public void setServerChangeListener(OnClickListener ocl){
if (menu == null) return;
RelativeLayout changeSrv = (RelativeLayout) menu.findViewById(R.id.lServer);
changeSrv.setOnClickListener(ocl);
ImageView changeSrvImg = (ImageView) menu.findViewById(R.id.ivChangeSrv);
changeSrvImg.setVisibility(View.VISIBLE);
}
public void updateSMServer(SynoServer server){
if (menu == null) return;
TextView svName = (TextView) menu.findViewById(R.id.tvSrvName);
TextView svURL = (TextView) menu.findViewById(R.id.tvSrvUrl);
if (server != null && server.isConnected()){
svName.setText(server.getNickname());
svURL.setText(server.getUser());
}
else{
svName.setText(R.string.empty_not_connected);
svURL.setText("");
}
}
private SynodroidFragment getDisplayFragment(){
FragmentManager fm = getSupportFragmentManager();
SynodroidFragment sf = null;
try{
sf = (SynodroidFragment) fm.findFragmentById(R.id.fragment_download);
} catch (Exception ed){
sf = null;
}
if (sf == null){
try{
sf = (SynodroidFragment) fm.findFragmentById(R.id.fragment_browser);
} catch (Exception eb){
sf = null;
}
}
if (sf == null){
try{
sf = (SynodroidFragment) fm.findFragmentById(R.id.fragment_file);
} catch (Exception ef){
sf = null;
}
}
if (sf == null){
try{
sf = (SynodroidFragment) fm.findFragmentById(R.id.fragment_search);
} catch (Exception es){
sf = null;
}
}
return sf;
}
/**
* Create the connection and error dialogs
*/
@Override
protected Dialog onCreateDialog(int id) {
super.onCreateDialog(id);
Dialog dialog = null;
switch (id) {
// No server have been yet configured
case NO_SERVER_DIALOG_ID:
AlertDialog.Builder builderNoServer = new AlertDialog.Builder(BaseActivity.this);
builderNoServer.setTitle(R.string.dialog_title_information);
builderNoServer.setMessage(getString(R.string.no_server_configured));
builderNoServer.setCancelable(true);
builderNoServer.setPositiveButton(getString(R.string.button_yesplease), new android.content.DialogInterface.OnClickListener() {
// Launch the Preference activity
public void onClick(DialogInterface dialogP, int whichP) {
okToCreateAServer();
}
});
builderNoServer.setNegativeButton(getString(R.string.button_nothanks), new android.content.DialogInterface.OnClickListener() {
// Launch the Preference activity
public void onClick(DialogInterface dialogP, int whichP) {
alreadyCanceled = true;
}
});
dialog = builderNoServer.create();
break;
case OTP_REQUEST_DIALOG_ID:
final Synodroid app = (Synodroid) getApplication();
final SynodroidFragment current_fragment = getDisplayFragment();
current_fragment.setOTPDialog(true);
AlertDialog.Builder otp_request = new AlertDialog.Builder(BaseActivity.this);
otp_request.setTitle(R.string.title_otp);
LayoutInflater otp_inflater = getLayoutInflater();
View otp_v = otp_inflater.inflate(R.layout.otp_request, null);
final EditText otp_edt = (EditText) otp_v.findViewById(R.id.otp_pass);
otp_edt.setText("");
otp_request.setView(otp_v);
otp_request.setPositiveButton(getString(android.R.string.ok), new android.content.DialogInterface.OnClickListener() {
// Launch the Preference activity
public void onClick(DialogInterface dialogP, int whichP) {
try{
app.connectServer(current_fragment, app.getServer(), current_fragment.getPostOTPActions(), false, otp_edt.getText().toString());
current_fragment.setOTPDialog(false);
current_fragment.resetPostOTPActions();
removeDialog(OTP_REQUEST_DIALOG_ID);
}
catch (Exception e){
//Cannot clear all when download fragment not accessible.
try{
if (((Synodroid)getApplication()).DEBUG) Log.e(Synodroid.DS_TAG, "HomeActivity: App tried to call OTP login when download fragment hidden.");
}catch (Exception ex){/*DO NOTHING*/}
}
}
});
dialog = otp_request.create();
break;
}
return dialog;
}
/**
* The user agree to create a new as no server has been configured or no server is suitable for the current connection
*/
private void okToCreateAServer() {
final SharedPreferences preferences = getSharedPreferences(PREFERENCE_AUTO, Activity.MODE_PRIVATE);
preferences.edit().putBoolean(PREFERENCE_AUTO_CREATENOW, true).commit();
showPreferenceActivity();
}
/**
* Show the preference activity
*/
private void showPreferenceActivity() {
Intent next = new Intent();
next.setClass(this, DownloadPreferenceActivity.class);
startActivity(next);
}
/**
* Show the dialog to connect to a server
*/
public void showDialogToConnect(boolean autoConnectIfOnlyOneServerP, final List<SynoAction> actionQueueP, final boolean automated) {
SharedPreferences generalPref = getSharedPreferences(PREFERENCE_GENERAL, Activity.MODE_PRIVATE);
SharedPreferences serverPref = getSharedPreferences(PREFERENCE_SERVER, Activity.MODE_PRIVATE);
boolean autoDetect = generalPref.getBoolean(PREFERENCE_AUTO_DSM, true);
String defaultSrv = serverPref.getString(PREFERENCE_DEF_SRV, "0");
final Activity a = this;
if (!connectDialogOpened && a != null) {
final Synodroid app = (Synodroid) a.getApplication();
if (app != null){
if (!app.isNetworkAvailable())
return;
final ArrayList<SynoServer> servers = PreferenceFacade.loadServers(a, PreferenceManager.getDefaultSharedPreferences(a), app.DEBUG, autoDetect);
// If at least one server
if (servers.size() != 0) {
// If more than 1 server OR if we don't want to autoconnect then
// show the dialog
if (servers.size() > 1 || !autoConnectIfOnlyOneServerP) {
boolean skip = false;
String[] serversTitle = new String[servers.size()];
for (int iLoop = 0; iLoop < servers.size(); iLoop++) {
SynoServer s = servers.get(iLoop);
serversTitle[iLoop] = s.getNickname();
//Check if default server and connect to it skipping the dialog...
if (defaultSrv.equals(s.getID()) && autoConnectIfOnlyOneServerP){
app.connectServer(getDisplayFragment(), s, actionQueueP, automated);
skip = true;
}
}
if (!skip){
connectDialogOpened = true;
AlertDialog.Builder builder = new AlertDialog.Builder(a);
builder.setTitle(getString(R.string.menu_connect));
// When the user select a server
builder.setItems(serversTitle, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
SynoServer server = servers.get(item);
// Change the server
app.connectServer(getDisplayFragment(), server, actionQueueP, automated);
dialog.dismiss();
}
});
AlertDialog connectDialog = builder.create();
try {
connectDialog.show();
} catch (BadTokenException e) {
// Unable to show dialog probably because intent has been closed. Ignoring...
}
connectDialog.setOnDismissListener(new OnDismissListener() {
public void onDismiss(DialogInterface dialog) {
connectDialogOpened = false;
}
});
}
} else {
// Auto connect to the first server
if (servers.size() > 0) {
SynoServer server = servers.get(0);
// Change the server
app.connectServer(getDisplayFragment(), server, actionQueueP, automated);
}
}
}
// No server then show the dialog to configure a server
else {
// Only if the EULA has been accepted. If the EULA has not been
// accepted, it means that the EULA is currenlty being displayed so
// don't show the "Wizard" dialog
if (EulaHelper.hasAcceptedEula(a) && !alreadyCanceled) {
try {
a.showDialog(NO_SERVER_DIALOG_ID);
} catch (Exception e) {
// Unable to show dialog probably because intent has been closed or the dialog is already displayed. Ignoring...
}
}
}
}
}
}
@Override
protected void onResume() {
super.onResume();
//Make sure the menu is hidden for when the back button is pressed
if (menu != null) menu.showContent(false);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
// ignore orientation change
super.onConfigurationChanged(newConfig);
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
mActivityHelper.onPostCreate(savedInstanceState);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return mActivityHelper.onKeyDown(keyCode, event) ||
super.onKeyDown(keyCode, event);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
return mActivityHelper.onCreateOptionsMenu(menu) || super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
return mActivityHelper.onOptionsItemSelected(item) || super.onOptionsItemSelected(item);
}
@Override
public void onBackPressed() {
if (menu != null && menu.isMenuShowing()) {
menu.showContent();
} else {
super.onBackPressed();
}
}
public void attachSecondarySlidingMenu(){
if (menu != null){
menu.setMode(SlidingMenu.LEFT_RIGHT);
menu.setSecondaryMenu(R.layout.sliding_bookmarks);
menu.setSecondaryShadowDrawable(R.drawable.shadow_right);
}
}
public void attachSlidingMenu(){
attachSlidingMenu(null);
}
public void attachSlidingMenu(SynoServer srv){
// configure the SlidingMenu
menu = new SlidingMenu(this);
menu.setMode(SlidingMenu.LEFT);
menu.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);
menu.setShadowWidthRes(R.dimen.shadow_width);
menu.setShadowDrawable(R.drawable.shadow);
menu.setBehindOffsetRes(R.dimen.slidingmenu_offset);
menu.setFadeDegree(0.90f);
menu.attachToActivity(this, SlidingMenu.SLIDING_WINDOW);
menu.setMenu(R.layout.home_menu_frame);
SlidingMenuAdapter adapter = new SlidingMenuAdapter(this);
adapter.add(new SlidingMenuItem(getString(R.string.sliding_downloads), R.drawable.ic_download, SMNU_DL));
adapter.add(new SlidingMenuItem(getString(R.string.sliding_browser), R.drawable.ic_browser, SMNU_BR));
adapter.add(new SlidingMenuItem(getString(R.string.sliding_files), R.drawable.ic_file, SMNU_FI));
//adapter.add(new SlidingMenuItem(getString(R.string.sliding_rss), R.drawable.ic_rss, SMNU_RS));
adapter.add(new SlidingMenuItem(getString(R.string.sliding_search), R.drawable.ic_title_search, SMNU_SE));
adapter.add(new SlidingMenuItem(getString(R.string.menu_parameter), R.drawable.ic_settings, SMNU_SET));
adapter.add(new SlidingMenuItem(getString(R.string.help), R.drawable.ic_help, SMNU_HP));
adapter.add(new SlidingMenuItem(getString(R.string.sliding_about), R.drawable.ic_about, SMNU_AB));
final ListView menuList = (ListView) menu.findViewById(R.id.lvMenu);
final Activity act = this;
menuList.setAdapter(adapter);
menuList.setOnItemClickListener(new ListView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> a, View v, int i, long l) {
try {
menuListSelectedItem = (SlidingMenuItem) menuList.getItemAtPosition(i);
switch (menuListSelectedItem.id){
default:
case SMNU_DL:
try{
if (((Synodroid)getApplication()).DEBUG) Log.v(Synodroid.DS_TAG,"SlidingMenu: Menu download selected.");
}catch (Exception ex){/*DO NOTHING*/}
if (!(act instanceof HomeActivity)){
final Intent intent = new Intent(act, HomeActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
act.startActivity(intent);
}
else{
menu.showContent(true);
}
break;
case SMNU_BR:
try{
if (((Synodroid)getApplication()).DEBUG) Log.v(Synodroid.DS_TAG,"SlidingMenu: Menu browser selected.");
}catch (Exception ex){/*DO NOTHING*/}
if (!(act instanceof BrowserActivity)){
final Intent intent = new Intent(act, BrowserActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
act.startActivity(intent);
}
else{
menu.showContent(true);
}
break;
case SMNU_FI:
try{
if (((Synodroid)getApplication()).DEBUG) Log.v(Synodroid.DS_TAG,"SlidingMenu: Menu file selected.");
}catch (Exception ex){/*DO NOTHING*/}
if (!(act instanceof FileActivity)){
final Intent intent = new Intent(act, FileActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
act.startActivity(intent);
}
else{
menu.showContent(true);
}
break;
case SMNU_RS:
menu.showContent(true);
Crouton.makeText(BaseActivity.this, R.string.not_yet_implemented, Synodroid.CROUTON_ALERT).show();
break;
case SMNU_SE:
try{
if (((Synodroid)getApplication()).DEBUG) Log.v(Synodroid.DS_TAG,"SlidingMenu: Menu search selected.");
}catch (Exception ex){/*DO NOTHING*/}
if (!(act instanceof SearchActivity)){
showSearchActivity(true);
}
else {
menu.showContent(true);
}
break;
case SMNU_HP:
try{
if (((Synodroid)getApplication()).DEBUG) Log.v(Synodroid.DS_TAG,"SlidingMenu: Menu help selected.");
}catch (Exception ex){/*DO NOTHING*/}
if (!(act instanceof HelpActivity)){
// Starting new intent
Intent next = new Intent();
next.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
next.setClass(act, HelpActivity.class);
startActivity(next);
}
else{
menu.showContent(true);
}
break;
case SMNU_AB:
try{
if (((Synodroid)getApplication()).DEBUG) Log.v(Synodroid.DS_TAG,"SlidingMenu: Menu about selected.");
}catch (Exception ex){/*DO NOTHING*/}
if (!(act instanceof AboutActivity)){
// Starting new intent
Intent next = new Intent();
next.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
next.setClass(act, AboutActivity.class);
startActivity(next);
}
else{
menu.showContent(true);
}
break;
case SMNU_SET:
try{
if (((Synodroid)getApplication()).DEBUG) Log.v(Synodroid.DS_TAG,"SlidingMenu: Menu settings selected.");
}catch (Exception ex){/*DO NOTHING*/}
Intent next = new Intent();
next.setClass(act, DownloadPreferenceActivity.class);
startActivity(next);
break;
}
}
catch(Exception e) {
Log.e(Synodroid.DS_TAG, "Cannot get item at position "+i+".", e);
}
}
});
if (srv != null){
updateSMServer(srv);
}
if (this instanceof HomeActivity || this instanceof SearchActivity || this instanceof BrowserActivity || this instanceof FileActivity ){
setServerChangeListener(new android.view.View.OnClickListener(){
public void onClick(View v) {
menu.showContent();
showDialogToConnect(false, null, false);
}
});
}
}
/**
* Returns the {@link ActivityHelper} object associated with this activity.
*/
public ActivityHelper getActivityHelper() {
return mActivityHelper;
}
/**
* Returns the {@link ActivityHelper} object associated with this activity.
*/
public ActionModeHelper getActionModeHelper() {
return mActionModeHelper;
}
/**
* Takes a given intent and either starts a new activity to handle it (the default behavior),
* or creates/updates a fragment (in the case of a multi-pane activity) that can handle the
* intent.
*
* Must be called from the main (UI) thread.
*/
public void openActivityOrFragment(Intent intent) {
// Default implementation simply calls startActivity
startActivity(intent);
}
/**
* Converts an intent into a {@link Bundle} suitable for use as fragment arguments.
*/
public static Bundle intentToFragmentArguments(Intent intent) {
Bundle arguments = new Bundle();
if (intent == null) {
return arguments;
}
final Uri data = intent.getData();
if (data != null) {
arguments.putParcelable("_uri", data);
}
final Bundle extras = intent.getExtras();
if (extras != null) {
arguments.putAll(intent.getExtras());
}
return arguments;
}
/**
* Converts a fragment arguments bundle into an intent.
*/
public static Intent fragmentArgumentsToIntent(Bundle arguments) {
Intent intent = new Intent();
if (arguments == null) {
return intent;
}
final Uri data = arguments.getParcelable("_uri");
if (data != null) {
intent.setData(data);
}
intent.putExtras(arguments);
intent.removeExtra("_uri");
return intent;
}
}