/* * Copyright (C) 2007-2013 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.libraryService; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.geometerplus.android.fbreader.api.TextPosition; import org.geometerplus.fbreader.Paths; import org.geometerplus.fbreader.book.AbstractBookCollection; import org.geometerplus.fbreader.book.Author; import org.geometerplus.fbreader.book.Book; import org.geometerplus.fbreader.book.BookEvent; import org.geometerplus.fbreader.book.BookQuery; import org.geometerplus.fbreader.book.Bookmark; import org.geometerplus.fbreader.book.BookmarkQuery; import org.geometerplus.fbreader.book.Filter; import org.geometerplus.fbreader.book.HighlightingStyle; import org.geometerplus.fbreader.book.SerializerUtil; import org.geometerplus.fbreader.book.Tag; import org.geometerplus.fbreader.book.UID; import org.geometerplus.zlibrary.core.filesystem.ZLFile; import org.geometerplus.zlibrary.text.view.ZLTextFixedPosition; import org.geometerplus.zlibrary.text.view.ZLTextPosition; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.os.IBinder; import android.os.RemoteException; public class BookCollectionShadow extends AbstractBookCollection implements ServiceConnection { private Context myContext; private volatile LibraryInterface myInterface; private Runnable myOnBindAction; private final BroadcastReceiver myReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { if (!hasListeners()) { return; } try { final String type = intent.getStringExtra("type"); if (LibraryService.BOOK_EVENT_ACTION.equals(intent.getAction())) { final Book book = SerializerUtil.deserializeBook(intent.getStringExtra("book")); fireBookEvent(BookEvent.valueOf(type), book); } else { fireBuildEvent(Status.valueOf(type)); } } catch (Exception e) { // ignore } } }; private static Runnable combined(final Runnable action0, final Runnable action1) { if (action0 == null) { return action1; } if (action1 == null) { return action0; } return new Runnable() { public void run() { action0.run(); action1.run(); } }; } public synchronized void bindToService(Context context, Runnable onBindAction) { if (myInterface != null && myContext == context) { if (onBindAction != null) { onBindAction.run(); } } else { myOnBindAction = combined(myOnBindAction, onBindAction); context.bindService( new Intent(context, LibraryService.class), this, LibraryService.BIND_AUTO_CREATE ); myContext = context; } } public synchronized void unbind() { if (myContext != null && myInterface != null) { try { myContext.unregisterReceiver(myReceiver); } catch (Exception e) { e.printStackTrace(); } try { myContext.unbindService(this); } catch (Exception e) { e.printStackTrace(); } myInterface = null; myContext = null; } } public synchronized void reset(boolean force) { if (myInterface != null) { try { myInterface.reset( Collections.singletonList(Paths.BooksDirectoryOption().getValue()), force ); } catch (RemoteException e) { } } } public synchronized int size() { if (myInterface == null) { return 0; } try { return myInterface.size(); } catch (RemoteException e) { return 0; } } public synchronized Status status() { if (myInterface == null) { return Status.NotStarted; } try { return Status.valueOf(myInterface.status()); } catch (Throwable t) { return Status.NotStarted; } } public synchronized List<Book> books(BookQuery query) { if (myInterface == null) { return Collections.emptyList(); } try { return SerializerUtil.deserializeBookList(myInterface.books(SerializerUtil.serialize(query))); } catch (RemoteException e) { return Collections.emptyList(); } } public synchronized boolean hasBooks(Filter filter) { if (myInterface == null) { return false; } try { return myInterface.hasBooks(SerializerUtil.serialize(new BookQuery(filter, 1))); } catch (RemoteException e) { return false; } } public synchronized List<Book> recentBooks() { if (myInterface == null) { return Collections.emptyList(); } try { return SerializerUtil.deserializeBookList(myInterface.recentBooks()); } catch (RemoteException e) { return Collections.emptyList(); } } public synchronized Book getRecentBook(int index) { if (myInterface == null) { return null; } try { return SerializerUtil.deserializeBook(myInterface.getRecentBook(index)); } catch (RemoteException e) { return null; } } public synchronized Book getBookByFile(ZLFile file) { if (myInterface == null) { return null; } try { return SerializerUtil.deserializeBook(myInterface.getBookByFile(file.getPath())); } catch (RemoteException e) { return null; } } public synchronized Book getBookById(long id) { if (myInterface == null) { return null; } try { return SerializerUtil.deserializeBook(myInterface.getBookById(id)); } catch (RemoteException e) { return null; } } public synchronized Book getBookByUid(UID uid) { if (myInterface == null) { return null; } try { return SerializerUtil.deserializeBook(myInterface.getBookByUid(uid.Type, uid.Id)); } catch (RemoteException e) { return null; } } public synchronized List<Author> authors() { if (myInterface == null) { return Collections.emptyList(); } try { final List<String> strings = myInterface.authors(); final List<Author> authors = new ArrayList<Author>(strings.size()); for (String s : strings) { authors.add(Util.stringToAuthor(s)); } return authors; } catch (RemoteException e) { return Collections.emptyList(); } } public synchronized List<Tag> tags() { if (myInterface == null) { return Collections.emptyList(); } try { final List<String> strings = myInterface.tags(); final List<Tag> tags = new ArrayList<Tag>(strings.size()); for (String s : strings) { tags.add(Util.stringToTag(s)); } return tags; } catch (RemoteException e) { return Collections.emptyList(); } } public synchronized boolean hasSeries() { if (myInterface != null) { try { return myInterface.hasSeries(); } catch (RemoteException e) { } } return false; } public synchronized List<String> series() { if (myInterface == null) { return Collections.emptyList(); } try { return myInterface.series(); } catch (RemoteException e) { return Collections.emptyList(); } } public synchronized List<String> titles(BookQuery query) { if (myInterface == null) { return Collections.emptyList(); } try { return myInterface.titles(SerializerUtil.serialize(query)); } catch (RemoteException e) { return Collections.emptyList(); } } public synchronized List<String> firstTitleLetters() { if (myInterface == null) { return Collections.emptyList(); } try { return myInterface.firstTitleLetters(); } catch (RemoteException e) { return Collections.emptyList(); } } public synchronized boolean saveBook(Book book, boolean force) { if (myInterface == null) { return false; } try { return myInterface.saveBook(SerializerUtil.serialize(book), force); } catch (RemoteException e) { return false; } } public synchronized void removeBook(Book book, boolean deleteFromDisk) { if (myInterface != null) { try { myInterface.removeBook(SerializerUtil.serialize(book), deleteFromDisk); } catch (RemoteException e) { } } } public synchronized void addBookToRecentList(Book book) { if (myInterface != null) { try { myInterface.addBookToRecentList(SerializerUtil.serialize(book)); } catch (RemoteException e) { } } } public synchronized List<String> labels() { if (myInterface != null) { try { return myInterface.labels(); } catch (RemoteException e) { } } return Collections.emptyList(); } public synchronized ZLTextPosition getStoredPosition(long bookId) { if (myInterface == null) { return null; } try { final TextPosition position = myInterface.getStoredPosition(bookId); if (position == null) { return null; } return new ZLTextFixedPosition( position.ParagraphIndex, position.ElementIndex, position.CharIndex ); } catch (RemoteException e) { return null; } } public synchronized void storePosition(long bookId, ZLTextPosition position) { if (position != null && myInterface != null) { try { myInterface.storePosition(bookId, new TextPosition( position.getParagraphIndex(), position.getElementIndex(), position.getCharIndex() )); } catch (RemoteException e) { } } } public synchronized boolean isHyperlinkVisited(Book book, String linkId) { if (myInterface == null) { return false; } try { return myInterface.isHyperlinkVisited(SerializerUtil.serialize(book), linkId); } catch (RemoteException e) { return false; } } public synchronized void markHyperlinkAsVisited(Book book, String linkId) { if (myInterface != null) { try { myInterface.markHyperlinkAsVisited(SerializerUtil.serialize(book), linkId); } catch (RemoteException e) { } } } public synchronized List<Bookmark> bookmarks(BookmarkQuery query) { if (myInterface == null) { return Collections.emptyList(); } try { return SerializerUtil.deserializeBookmarkList( myInterface.bookmarks(SerializerUtil.serialize(query)) ); } catch (RemoteException e) { return Collections.emptyList(); } } public synchronized void saveBookmark(Bookmark bookmark) { if (myInterface != null) { try { bookmark.update(SerializerUtil.deserializeBookmark( myInterface.saveBookmark(SerializerUtil.serialize(bookmark)) )); } catch (RemoteException e) { } } } public synchronized void deleteBookmark(Bookmark bookmark) { if (myInterface != null) { try { myInterface.deleteBookmark(SerializerUtil.serialize(bookmark)); } catch (RemoteException e) { } } } public synchronized HighlightingStyle getHighlightingStyle(int styleId) { if (myInterface == null) { return null; } try { return SerializerUtil.deserializeStyle(myInterface.getHighlightingStyle(styleId)); } catch (RemoteException e) { return null; } } public synchronized List<HighlightingStyle> highlightingStyles() { if (myInterface == null) { return Collections.emptyList(); } try { return SerializerUtil.deserializeStyleList(myInterface.highlightingStyles()); } catch (RemoteException e) { return Collections.emptyList(); } } public synchronized void saveHighlightingStyle(HighlightingStyle style) { if (myInterface != null) { try { myInterface.saveHighlightingStyle(SerializerUtil.serialize(style)); } catch (RemoteException e) { // ignore } } } // method from ServiceConnection interface public synchronized void onServiceConnected(ComponentName name, IBinder service) { myInterface = LibraryInterface.Stub.asInterface(service); if (myOnBindAction != null) { myOnBindAction.run(); myOnBindAction = null; } if (myContext != null) { myContext.registerReceiver(myReceiver, new IntentFilter(LibraryService.BOOK_EVENT_ACTION)); myContext.registerReceiver(myReceiver, new IntentFilter(LibraryService.BUILD_EVENT_ACTION)); } } // method from ServiceConnection interface public synchronized void onServiceDisconnected(ComponentName name) { } }