/* * Copyright (C) 2010-2012 Geometer Plus <contact@geometerplus.com> * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ package org.geometerplus.android.fbreader.network; import java.util.*; import android.app.AlertDialog; import android.content.Intent; import android.content.DialogInterface; import android.net.Uri; import android.os.Bundle; import android.view.*; import android.widget.*; import org.geometerplus.zlibrary.core.network.ZLNetworkManager; import org.geometerplus.zlibrary.core.resources.ZLResource; import org.geometerplus.zlibrary.core.util.ZLBoolean3; import org.geometerplus.zlibrary.ui.android.network.SQLiteCookieDatabase; import org.geometerplus.fbreader.tree.FBTree; import org.geometerplus.fbreader.network.*; import org.geometerplus.fbreader.network.tree.*; import org.geometerplus.android.fbreader.tree.TreeActivity; import org.geometerplus.android.fbreader.network.action.*; import org.geometerplus.android.util.UIUtil; public abstract class NetworkLibraryActivity extends TreeActivity implements ListView.OnScrollListener, NetworkLibrary.ChangeListener { static final String OPEN_CATALOG_ACTION = "android.fbreader.action.OPEN_NETWORK_CATALOG"; BookDownloaderServiceConnection Connection; final List<Action> myOptionsMenuActions = new ArrayList<Action>(); final List<Action> myContextMenuActions = new ArrayList<Action>(); final List<Action> myListClickActions = new ArrayList<Action>(); private Intent myDeferredIntent; private boolean mySingleCatalog; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); AuthenticationActivity.initCredentialsCreator(this); SQLiteCookieDatabase.init(this); Connection = new BookDownloaderServiceConnection(); bindService( new Intent(getApplicationContext(), BookDownloaderService.class), Connection, BIND_AUTO_CREATE ); setListAdapter(new NetworkLibraryAdapter(this)); final Intent intent = getIntent(); init(intent); myDeferredIntent = null; setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL); if (getCurrentTree() instanceof RootTree) { mySingleCatalog = intent.getBooleanExtra("SingleCatalog", false); if (!NetworkLibrary.Instance().isInitialized()) { Util.initLibrary(this); myDeferredIntent = intent; } else { NetworkLibrary.Instance().fireModelChangedEvent(NetworkLibrary.ChangeListener.Code.SomeCode); openTreeByIntent(intent); } } getListView().setOnScrollListener(this); } @Override protected NetworkTree getTreeByKey(FBTree.Key key) { final NetworkLibrary library = NetworkLibrary.Instance(); final NetworkTree tree = library.getTreeByKey(key); return tree != null ? tree : library.getRootTree(); } @Override protected void onStart() { super.onStart(); NetworkLibrary.Instance().addChangeListener(this); } @Override public void onResume() { super.onResume(); getListView().setOnCreateContextMenuListener(this); NetworkLibrary.Instance().fireModelChangedEvent(NetworkLibrary.ChangeListener.Code.SomeCode); } @Override protected void onStop() { NetworkLibrary.Instance().removeChangeListener(this); super.onStop(); } @Override public void onDestroy() { if (Connection != null) { unbindService(Connection); Connection = null; } super.onDestroy(); } private boolean openTreeByIntent(Intent intent) { if (OPEN_CATALOG_ACTION.equals(intent.getAction())) { final Uri uri = intent.getData(); if (uri != null) { final NetworkTree tree = NetworkLibrary.Instance().getCatalogTreeByUrl(uri.toString()); if (tree != null) { checkAndRun(new OpenCatalogAction(this), tree); return true; } } } return false; } @Override protected void onNewIntent(Intent intent) { if (!openTreeByIntent(intent)) { super.onNewIntent(intent); } } @Override public boolean onSearchRequested() { final NetworkTree tree = (NetworkTree)getCurrentTree(); final RunSearchAction action = new RunSearchAction(this, false); if (action.isVisible(tree) && action.isEnabled(tree)) { action.run(tree); return true; } else { return false; } } @Override public boolean isTreeSelected(FBTree tree) { return false; } @Override protected boolean isTreeInvisible(FBTree tree) { return tree instanceof RootTree && (mySingleCatalog || ((RootTree)tree).IsFake); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) { final NetworkItemsLoader loader = NetworkLibrary.Instance().getStoredLoader((NetworkTree)getCurrentTree()); if (loader != null) { loader.interrupt(); } } return super.onKeyDown(keyCode, event); } private void fillOptionsMenuList() { myOptionsMenuActions.add(new RunSearchAction(this, false)); myOptionsMenuActions.add(new AddCustomCatalogAction(this)); myOptionsMenuActions.add(new RefreshRootCatalogAction(this)); myOptionsMenuActions.add(new LanguageFilterAction(this)); myOptionsMenuActions.add(new ReloadCatalogAction(this)); myOptionsMenuActions.add(new SignInAction(this)); myOptionsMenuActions.add(new SignUpAction(this)); myOptionsMenuActions.add(new SignOutAction(this)); myOptionsMenuActions.add(new TopupAction(this)); myOptionsMenuActions.add(new BuyBasketBooksAction(this)); myOptionsMenuActions.add(new ClearBasketAction(this)); } private void fillContextMenuList() { myContextMenuActions.add(new OpenCatalogAction(this)); myContextMenuActions.add(new OpenInBrowserAction(this)); myContextMenuActions.add(new RunSearchAction(this, true)); myContextMenuActions.add(new AddCustomCatalogAction(this)); myContextMenuActions.add(new SignOutAction(this)); myContextMenuActions.add(new TopupAction(this)); myContextMenuActions.add(new SignInAction(this)); myContextMenuActions.add(new EditCustomCatalogAction(this)); myContextMenuActions.add(new RemoveCustomCatalogAction(this)); myContextMenuActions.add(new BuyBasketBooksAction(this)); myContextMenuActions.add(new ClearBasketAction(this)); } private void fillListClickList() { myListClickActions.add(new OpenCatalogAction(this)); myListClickActions.add(new OpenInBrowserAction(this)); myListClickActions.add(new RunSearchAction(this, true)); myListClickActions.add(new AddCustomCatalogAction(this)); myListClickActions.add(new TopupAction(this)); myListClickActions.add(new ShowBookInfoAction(this)); } private List<? extends Action> getContextMenuActions(NetworkTree tree) { return tree instanceof NetworkBookTree ? NetworkBookActions.getContextMenuActions(this, (NetworkBookTree)tree, Connection) : myContextMenuActions; } @Override public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { if (myContextMenuActions.isEmpty()) { fillContextMenuList(); } final int position = ((AdapterView.AdapterContextMenuInfo)menuInfo).position; final NetworkTree tree = (NetworkTree)getListAdapter().getItem(position); if (tree != null) { menu.setHeaderTitle(tree.getName()); for (Action a : getContextMenuActions(tree)) { if (a.isVisible(tree) && a.isEnabled(tree)) { menu.add(0, a.Code, 0, a.getContextLabel(tree)); } } } } @Override public boolean onContextItemSelected(MenuItem item) { final int position = ((AdapterView.AdapterContextMenuInfo)item.getMenuInfo()).position; final NetworkTree tree = (NetworkTree)getListAdapter().getItem(position); if (tree != null) { for (Action a : getContextMenuActions(tree)) { if (a.Code == item.getItemId()) { checkAndRun(a, tree); return true; } } } return super.onContextItemSelected(item); } @Override public void onListItemClick(ListView listView, View view, int position, long rowId) { if (myListClickActions.isEmpty()) { fillListClickList(); } final NetworkTree tree = (NetworkTree)getListAdapter().getItem(position); for (Action a : myListClickActions) { if (a.isVisible(tree) && a.isEnabled(tree)) { checkAndRun(a, tree); return; } } listView.showContextMenuForChild(view); } @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); if (myOptionsMenuActions.isEmpty()) { fillOptionsMenuList(); } // final NetworkTree tree = (NetworkTree)getCurrentTree(); for (Action a : myOptionsMenuActions) { final MenuItem item = menu.add(0, a.Code, Menu.NONE, ""); if (a.IconId != -1) { item.setIcon(a.IconId); } } return true; } @Override public boolean onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); final NetworkTree tree = (NetworkTree)getCurrentTree(); for (Action a : myOptionsMenuActions) { final MenuItem item = menu.findItem(a.Code); if (a.isVisible(tree)) { item.setVisible(true); item.setEnabled(a.isEnabled(tree)); item.setTitle(a.getOptionsLabel(tree)); } else { item.setVisible(false); } } return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { final NetworkTree tree = (NetworkTree)getCurrentTree(); for (Action a : myOptionsMenuActions) { if (a.Code == item.getItemId()) { checkAndRun(a, tree); break; } } return true; } private void updateLoadingProgress() { final NetworkLibrary library = NetworkLibrary.Instance(); final NetworkTree tree = (NetworkTree)getCurrentTree(); final NetworkTree lTree = getLoadableNetworkTree(tree); final NetworkTree sTree = RunSearchAction.getSearchTree(tree); setProgressBarIndeterminateVisibility( library.isUpdateInProgress() || library.isLoadingInProgress(lTree) || library.isLoadingInProgress(sTree) ); } // method from NetworkLibrary.ChangeListener public void onLibraryChanged(final NetworkLibrary.ChangeListener.Code code, final Object[] params) { runOnUiThread(new Runnable() { public void run() { switch (code) { default: updateLoadingProgress(); getListAdapter().replaceAll(getCurrentTree().subTrees()); //getListView().invalidateViews(); break; case InitializationFailed: showInitLibraryDialog((String)params[0]); break; case InitializationFinished: NetworkLibrary.Instance().runBackgroundUpdate(false); if (myDeferredIntent != null) { openTreeByIntent(myDeferredIntent); myDeferredIntent = null; } break; case Found: openTree((NetworkTree)params[0]); break; case NotFound: UIUtil.showErrorMessage(NetworkLibraryActivity.this, "emptyNetworkSearchResults"); getListView().invalidateViews(); break; case EmptyCatalog: UIUtil.showErrorMessage(NetworkLibraryActivity.this, "emptyCatalog"); break; case NetworkError: UIUtil.showMessageText(NetworkLibraryActivity.this, (String)params[0]); break; } } }); } private static NetworkTree getLoadableNetworkTree(NetworkTree tree) { while (tree instanceof NetworkAuthorTree || tree instanceof NetworkSeriesTree) { if (tree.Parent instanceof NetworkTree) { tree = (NetworkTree)tree.Parent; } else { return null; } } return tree; } @Override protected void onCurrentTreeChanged() { NetworkLibrary.Instance().fireModelChangedEvent(NetworkLibrary.ChangeListener.Code.SomeCode); } private void showInitLibraryDialog(String error) { final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { if (which == DialogInterface.BUTTON_POSITIVE) { Util.initLibrary(NetworkLibraryActivity.this); } else { finish(); } } }; final ZLResource dialogResource = ZLResource.resource("dialog"); final ZLResource boxResource = dialogResource.getResource("networkError"); final ZLResource buttonResource = dialogResource.getResource("button"); new AlertDialog.Builder(this) .setTitle(boxResource.getResource("title").getValue()) .setMessage(error) .setIcon(0) .setPositiveButton(buttonResource.getResource("tryAgain").getValue(), listener) .setNegativeButton(buttonResource.getResource("cancel").getValue(), listener) .setOnCancelListener(new DialogInterface.OnCancelListener() { public void onCancel(DialogInterface dialog) { listener.onClick(dialog, DialogInterface.BUTTON_NEGATIVE); } }) .create().show(); } private void checkAndRun(final Action action, final NetworkTree tree) { if (tree instanceof NetworkCatalogTree) { final NetworkCatalogTree catalogTree = (NetworkCatalogTree)tree; switch (catalogTree.getVisibility()) { case B3_FALSE: break; case B3_TRUE: action.run(tree); break; case B3_UNDEFINED: Util.runAuthenticationDialog(this, tree.getLink(), new Runnable() { public void run() { if (catalogTree.getVisibility() != ZLBoolean3.B3_TRUE) { return; } if (action.Code != ActionCode.SIGNIN) { action.run(tree); } } }); break; } } else { action.run(tree); } } public void onScroll(AbsListView view, int firstVisible, int visibleCount, int totalCount) { if (firstVisible + visibleCount + 1 >= totalCount) { final FBTree tree = getCurrentTree(); if (tree instanceof NetworkCatalogTree) { ((NetworkCatalogTree)tree).loadMoreChildren(totalCount); } } } public void onScrollStateChanged(AbsListView view, int state) { } }