/* * Copyright (C) 2010 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.HashMap; import java.util.LinkedList; import java.util.ArrayList; import android.content.Context; import android.content.Intent; import android.os.Handler; import android.os.Message; import android.view.MenuItem; import android.view.Menu; import org.geometerplus.zlibrary.core.network.ZLNetworkException; import org.geometerplus.fbreader.network.*; class NetworkView { private static NetworkView ourInstance; public static NetworkView Instance() { if (ourInstance == null) { ourInstance = new NetworkView(); } return ourInstance; } private NetworkView() { } private volatile boolean myInitialized; public boolean isInitialized() { return myInitialized; } public void initialize() throws ZLNetworkException { new SQLiteNetworkDatabase(); final NetworkLibrary library = NetworkLibrary.Instance(); library.initialize(); library.synchronize(); myActions.add(new NetworkBookActions()); myActions.add(new NetworkCatalogActions()); myActions.add(new SearchItemActions()); myActions.add(new RefillAccountActions()); myActions.add(new BrowserItemActions()); myActions.add(new AddCustomCatalogItemActions()); myActions.trimToSize(); myInitialized = true; } public void runBackgroundUpdate(boolean clearCache) throws ZLNetworkException { NetworkLibrary.Instance().runBackgroundUpdate(clearCache); } // This method MUST be called from main thread // This method has effect only when runBackgroundUpdate method has returned null public void finishBackgroundUpdate() { NetworkLibrary library = NetworkLibrary.Instance(); library.finishBackgroundUpdate(); library.synchronize(); fireModelChanged(); } /* * NetworkLibraryItem's actions */ private final ArrayList<NetworkTreeActions> myActions = new ArrayList<NetworkTreeActions>(); public NetworkTreeActions getActions(NetworkTree tree) { for (NetworkTreeActions actions: myActions) { if (actions.canHandleTree(tree)) { return actions; } } return null; } /* * OptionsMenu methods */ public boolean createOptionsMenu(Menu menu, NetworkTree tree) { if (!isInitialized()) { return false; } final NetworkTreeActions actions = getActions(tree); if (actions != null) { return actions.createOptionsMenu(menu, tree); } return false; } public boolean prepareOptionsMenu(NetworkBaseActivity activity, Menu menu, NetworkTree tree) { if (!isInitialized()) { return false; } final NetworkTreeActions actions = getActions(tree); if (actions != null) { return actions.prepareOptionsMenu(activity, menu, tree); } return false; } public boolean runOptionsMenu(NetworkBaseActivity activity, MenuItem item, NetworkTree tree) { if (!isInitialized()) { return false; } final NetworkTreeActions actions = getActions(tree); if (actions != null) { return actions.runAction(activity, tree, item.getItemId()); } return false; } /* * Code for loading network items (running items-loading service and managing items-loading runnables). */ private final HashMap<String, ItemsLoadingRunnable> myItemsLoadingRunnables = new HashMap<String, ItemsLoadingRunnable>(); public void startItemsLoading(Context context, String key, ItemsLoadingRunnable runnable) { boolean doDownload = false; synchronized (myItemsLoadingRunnables) { if (!myItemsLoadingRunnables.containsKey(key)) { myItemsLoadingRunnables.put(key, runnable); doDownload = true; } } if (doDownload) { context.startService( new Intent(context.getApplicationContext(), ItemsLoadingService.class) .putExtra(ItemsLoadingService.ITEMS_LOADING_RUNNABLE_KEY, key) ); } } ItemsLoadingRunnable getItemsLoadingRunnable(String key) { synchronized (myItemsLoadingRunnables) { return myItemsLoadingRunnables.get(key); } } void removeItemsLoadingRunnable(String key) { synchronized (myItemsLoadingRunnables) { ItemsLoadingRunnable runnable = myItemsLoadingRunnables.remove(key); if (runnable != null) { runnable.runFinishHandler(); } } } public final boolean containsItemsLoadingRunnable(String key) { return getItemsLoadingRunnable(key) != null; } public void tryResumeLoading(NetworkBaseActivity activity, NetworkTree tree, String key, Runnable expandRunnable) { final ItemsLoadingRunnable runnable = getItemsLoadingRunnable(key); if (runnable != null && runnable.tryResumeLoading()) { openTree(activity, tree, key); return; } if (runnable == null) { expandRunnable.run(); } else { runnable.runOnFinish(expandRunnable); } } /* * Notifying view's components from services */ public interface EventListener { void onModelChanged(); } private Handler myEventHandler; private LinkedList<EventListener> myEventListeners = new LinkedList<EventListener>(); /* * This method must be called only from main thread */ public final void addEventListener(EventListener listener) { synchronized (myEventListeners) { if (myEventHandler == null) { myEventHandler = new Handler() { @Override public void handleMessage(Message msg) { fireModelChanged(); } }; } if (listener != null) { myEventListeners.add(listener); } } } public final void removeEventListener(EventListener listener) { synchronized (myEventListeners) { myEventListeners.remove(listener); } } final void fireModelChangedAsync() { synchronized (myEventListeners) { if (myEventHandler != null) { myEventHandler.sendEmptyMessage(0); } } } final void fireModelChanged() { for (EventListener listener: myEventListeners) { listener.onModelChanged(); } } /* * Starting BookInfo activity */ private NetworkBookItem myBookInfoItem; public void showBookInfoActivity(Context context, NetworkBookItem book) { myBookInfoItem = book; context.startActivity( new Intent(context.getApplicationContext(), NetworkBookInfoActivity.class) ); } NetworkBookItem getBookInfoItem() { return myBookInfoItem; } /* * Opening Catalogs & managing opened catalogs stack */ private final LinkedList<NetworkTree> myOpenedStack = new LinkedList<NetworkTree>(); private final HashMap<String, NetworkCatalogActivity> myOpenedActivities = new HashMap<String, NetworkCatalogActivity>(); public void openTree(Context context, NetworkTree tree, String key) { final int level = tree.Level - 1; // tree.Level == 1 for catalog's root element if (level > myOpenedStack.size()) { throw new RuntimeException("Unable to open catalog with Level greater than the number of opened catalogs.\n" + "Catalog: " + tree.getName() + "\n" + "Level: " + level + "\n" + "Opened catalogs: " + myOpenedStack.size()); } while (level < myOpenedStack.size()) { myOpenedStack.removeLast(); } myOpenedStack.add(tree); context.startActivity( new Intent(context.getApplicationContext(), NetworkCatalogActivity.class) .putExtra(NetworkCatalogActivity.CATALOG_LEVEL_KEY, level) .putExtra(NetworkCatalogActivity.CATALOG_KEY_KEY, key) ); } void setOpenedActivity(String key, NetworkCatalogActivity activity) { if (activity == null) { myOpenedActivities.remove(key); } else { myOpenedActivities.put(key, activity); } } public NetworkCatalogActivity getOpenedActivity(String key) { return myOpenedActivities.get(key); } public NetworkTree getOpenedTree(int level) { if (level < 0 || level >= myOpenedStack.size()) { return null; } return myOpenedStack.get(level); } /* * Special view items item */ private ArrayList<NetworkTree> mySpecialItems = new ArrayList<NetworkTree>(); { mySpecialItems.add(new SearchItemTree()); mySpecialItems.add(new BrowserItemTree()); mySpecialItems.trimToSize(); } private final AddCustomCatalogItemTree myAddCustomCatalogItem = new AddCustomCatalogItemTree(); public ArrayList<NetworkTree> getSpecialItems() { return mySpecialItems; } public AddCustomCatalogItemTree getAddCustomCatalogItemTree() { return myAddCustomCatalogItem; } }