1 package org.coolreader.db; 2 3 import android.app.Service; 4 import android.content.Intent; 5 import android.os.Binder; 6 import android.os.Environment; 7 import android.os.Handler; 8 import android.os.IBinder; 9 import android.util.Log; 10 11 import org.coolreader.crengine.BookInfo; 12 import org.coolreader.crengine.Bookmark; 13 import org.coolreader.crengine.DeviceInfo; 14 import org.coolreader.crengine.FileInfo; 15 import org.coolreader.crengine.L; 16 import org.coolreader.crengine.Logger; 17 import org.coolreader.crengine.MountPathCorrector; 18 import org.coolreader.crengine.Utils; 19 20 import java.io.File; 21 import java.util.ArrayList; 22 import java.util.Collection; 23 24 public class CRDBService extends Service { 25 public static final Logger log = L.create("db"); 26 public static final Logger vlog = L.create("db", Log.ASSERT); 27 28 private MainDB mainDB = new MainDB(); 29 private CoverDB coverDB = new CoverDB(); 30 31 @Override onCreate()32 public void onCreate() { 33 log.i("onCreate()"); 34 mThread = new ServiceThread("crdb"); 35 mThread.start(); 36 execTask(new OpenDatabaseTask()); 37 } 38 reopenDatabase()39 public void reopenDatabase() { 40 execTask(new ReOpenDatabaseTask()); 41 } 42 43 @Override onStartCommand(Intent intent, int flags, int startId)44 public int onStartCommand(Intent intent, int flags, int startId) { 45 log.i("Received start id " + startId + ": " + intent); 46 // We want this service to continue running until it is explicitly 47 // stopped, so return sticky. 48 return START_STICKY; 49 } 50 51 @Override onDestroy()52 public void onDestroy() { 53 log.i("onDestroy()"); 54 execTask(new CloseDatabaseTask()); 55 mThread.stop(5000); 56 } 57 getDatabaseDir()58 private File getDatabaseDir() { 59 //File storage = Environment.getExternalStorageDirectory(); 60 File storage = DeviceInfo.EINK_NOOK ? new File("/media/") : Environment.getExternalStorageDirectory(); 61 File cr3dir = new File(storage, ".cr3"); 62 if (cr3dir.isDirectory()) 63 cr3dir.mkdirs(); 64 if (!cr3dir.isDirectory() || !cr3dir.canWrite()) { 65 log.w("Cannot use " + cr3dir + " for writing database, will use data directory instead"); 66 log.w("getFilesDir=" + getFilesDir() + " getDataDirectory=" + Environment.getDataDirectory()); 67 cr3dir = getFilesDir(); //Environment.getDataDirectory(); 68 } 69 log.i("DB directory: " + cr3dir); 70 return cr3dir; 71 } 72 73 private class OpenDatabaseTask extends Task { OpenDatabaseTask()74 public OpenDatabaseTask() { 75 super("OpenDatabaseTask"); 76 } 77 78 @Override work()79 public void work() { 80 open(); 81 } 82 open()83 private boolean open() { 84 File dir = getDatabaseDir(); 85 boolean res = mainDB.open(dir); 86 res = coverDB.open(dir) && res; 87 if (!res) { 88 mainDB.close(); 89 coverDB.close(); 90 } 91 return res; 92 } 93 94 } 95 96 private class CloseDatabaseTask extends Task { CloseDatabaseTask()97 public CloseDatabaseTask() { 98 super("CloseDatabaseTask"); 99 } 100 101 @Override work()102 public void work() { 103 close(); 104 } 105 close()106 private void close() { 107 clearCaches(); 108 mainDB.close(); 109 coverDB.close(); 110 } 111 } 112 113 private class ReOpenDatabaseTask extends Task { ReOpenDatabaseTask()114 public ReOpenDatabaseTask() { 115 super("ReOpenDatabaseTask"); 116 } 117 118 @Override work()119 public void work() { 120 close(); 121 open(); 122 } 123 open()124 private boolean open() { 125 File dir = getDatabaseDir(); 126 boolean res = mainDB.open(dir); 127 res = coverDB.open(dir) && res; 128 if (!res) { 129 mainDB.close(); 130 coverDB.close(); 131 } 132 return res; 133 } 134 close()135 private void close() { 136 clearCaches(); 137 mainDB.close(); 138 coverDB.close(); 139 } 140 } 141 142 private FlushDatabaseTask lastFlushTask; 143 private class FlushDatabaseTask extends Task { 144 private boolean force; FlushDatabaseTask(boolean force)145 public FlushDatabaseTask(boolean force) { 146 super("FlushDatabaseTask"); 147 this.force = force; 148 lastFlushTask = this; 149 } 150 @Override work()151 public void work() { 152 long elapsed = Utils.timeInterval(lastFlushTime); 153 if (force || (lastFlushTask == this && elapsed > MIN_FLUSH_INTERVAL)) { 154 mainDB.flush(); 155 coverDB.flush(); 156 if (!force) 157 lastFlushTime = Utils.timeStamp(); 158 } 159 } 160 } 161 clearCaches()162 private void clearCaches() { 163 mainDB.clearCaches(); 164 coverDB.clearCaches(); 165 } 166 167 private static final long MIN_FLUSH_INTERVAL = 30000; // 30 seconds 168 private long lastFlushTime; 169 170 /** 171 * Schedule flush. 172 */ flush()173 private void flush() { 174 execTask(new FlushDatabaseTask(false), MIN_FLUSH_INTERVAL); 175 } 176 177 /** 178 * Flush ASAP. 179 */ forceFlush()180 private void forceFlush() { 181 execTask(new FlushDatabaseTask(true)); 182 } 183 184 public static class FileInfoCache { 185 private ArrayList<FileInfo> list = new ArrayList<>(); add(FileInfo item)186 public void add(FileInfo item) { 187 list.add(item); 188 } clear()189 public void clear() { 190 list.clear(); 191 } 192 } 193 194 public interface SearchHistoryLoadingCallback { onSearchHistoryLoaded(ArrayList<String> searches)195 void onSearchHistoryLoaded(ArrayList<String> searches); 196 } 197 //======================================================================================= 198 // OPDS catalogs access code 199 //======================================================================================= 200 public interface OPDSCatalogsLoadingCallback { onOPDSCatalogsLoaded(ArrayList<FileInfo> catalogs)201 void onOPDSCatalogsLoaded(ArrayList<FileInfo> catalogs); 202 } 203 saveOPDSCatalog(final Long id, final String url, final String name, final String username, final String password)204 public void saveOPDSCatalog(final Long id, final String url, final String name, final String username, final String password) { 205 execTask(new Task("saveOPDSCatalog") { 206 @Override 207 public void work() { 208 mainDB.saveOPDSCatalog(id, url, name, username, password); 209 } 210 }); 211 } 212 saveSearchHistory(final BookInfo book, final String sHist)213 public void saveSearchHistory(final BookInfo book, final String sHist) { 214 execTask(new Task("saveSearchHistory") { 215 @Override 216 public void work() { 217 mainDB.saveSearchHistory(book, sHist); 218 } 219 }); 220 } 221 updateOPDSCatalogLastUsage(final String url)222 public void updateOPDSCatalogLastUsage(final String url) { 223 execTask(new Task("saveOPDSCatalog") { 224 @Override 225 public void work() { 226 mainDB.updateOPDSCatalogLastUsage(url); 227 } 228 }); 229 } 230 loadOPDSCatalogs(final OPDSCatalogsLoadingCallback callback, final Handler handler)231 public void loadOPDSCatalogs(final OPDSCatalogsLoadingCallback callback, final Handler handler) { 232 execTask(new Task("loadOPDSCatalogs") { 233 @Override 234 public void work() { 235 final ArrayList<FileInfo> list = new ArrayList<>(); 236 mainDB.loadOPDSCatalogs(list); 237 sendTask(handler, () -> callback.onOPDSCatalogsLoaded(list)); 238 } 239 }); 240 } 241 loadSearchHistory(final BookInfo book, final SearchHistoryLoadingCallback callback, final Handler handler)242 public void loadSearchHistory(final BookInfo book, final SearchHistoryLoadingCallback callback, final Handler handler) { 243 execTask(new Task("loadSearchHistory") { 244 @Override 245 public void work() { 246 final ArrayList<String> list = mainDB.loadSearchHistory(book); 247 sendTask(handler, () -> callback.onSearchHistoryLoaded(list)); 248 } 249 }); 250 } 251 removeOPDSCatalog(final Long id)252 public void removeOPDSCatalog(final Long id) { 253 execTask(new Task("removeOPDSCatalog") { 254 @Override 255 public void work() { 256 mainDB.removeOPDSCatalog(id); 257 } 258 }); 259 } 260 261 //======================================================================================= 262 // coverpage DB access code 263 //======================================================================================= 264 public interface CoverpageLoadingCallback { onCoverpageLoaded(FileInfo fileInfo, byte[] data)265 void onCoverpageLoaded(FileInfo fileInfo, byte[] data); 266 } 267 saveBookCoverpage(final FileInfo fileInfo, final byte[] data)268 public void saveBookCoverpage(final FileInfo fileInfo, final byte[] data) { 269 if (data == null) 270 return; 271 execTask(new Task("saveBookCoverpage") { 272 @Override 273 public void work() { 274 coverDB.saveBookCoverpage(fileInfo.getPathName(), data); 275 } 276 }); 277 flush(); 278 } 279 loadBookCoverpage(final FileInfo fileInfo, final CoverpageLoadingCallback callback, final Handler handler)280 public void loadBookCoverpage(final FileInfo fileInfo, final CoverpageLoadingCallback callback, final Handler handler) 281 { 282 execTask(new Task("loadBookCoverpage") { 283 @Override 284 public void work() { 285 final byte[] data = coverDB.loadBookCoverpage(fileInfo.getPathName()); 286 sendTask(handler, () -> callback.onCoverpageLoaded(fileInfo, data)); 287 } 288 }); 289 } 290 deleteCoverpage(final String bookId)291 public void deleteCoverpage(final String bookId) { 292 execTask(new Task("deleteCoverpage") { 293 @Override 294 public void work() { 295 coverDB.deleteCoverpage(bookId); 296 } 297 }); 298 flush(); 299 } 300 301 //======================================================================================= 302 // Item groups access code 303 //======================================================================================= 304 public interface ItemGroupsLoadingCallback { onItemGroupsLoaded(FileInfo parent)305 void onItemGroupsLoaded(FileInfo parent); 306 } 307 308 public interface FileInfoLoadingCallback { onFileInfoListLoaded(ArrayList<FileInfo> list)309 void onFileInfoListLoaded(ArrayList<FileInfo> list); 310 } 311 312 public interface RecentBooksLoadingCallback { onRecentBooksListLoaded(ArrayList<BookInfo> bookList)313 void onRecentBooksListLoaded(ArrayList<BookInfo> bookList); 314 } 315 316 public interface BookInfoLoadingCallback { onBooksInfoLoaded(BookInfo bookInfo)317 void onBooksInfoLoaded(BookInfo bookInfo); 318 } 319 320 public interface BookSearchCallback { onBooksFound(ArrayList<FileInfo> fileList)321 void onBooksFound(ArrayList<FileInfo> fileList); 322 } 323 loadGenresList(FileInfo parent, boolean showEmptyGenres, final ItemGroupsLoadingCallback callback, final Handler handler)324 public void loadGenresList(FileInfo parent, boolean showEmptyGenres, final ItemGroupsLoadingCallback callback, final Handler handler) { 325 final FileInfo p = new FileInfo(parent); 326 execTask(new Task("loadGenresList") { 327 @Override 328 public void work() { 329 mainDB.loadGenresList(p, showEmptyGenres); 330 sendTask(handler, () -> callback.onItemGroupsLoaded(p)); 331 } 332 }); 333 } 334 loadAuthorsList(FileInfo parent, final ItemGroupsLoadingCallback callback, final Handler handler)335 public void loadAuthorsList(FileInfo parent, final ItemGroupsLoadingCallback callback, final Handler handler) { 336 final FileInfo p = new FileInfo(parent); 337 execTask(new Task("loadAuthorsList") { 338 @Override 339 public void work() { 340 mainDB.loadAuthorsList(p); 341 sendTask(handler, () -> callback.onItemGroupsLoaded(p)); 342 } 343 }); 344 } 345 loadSeriesList(FileInfo parent, final ItemGroupsLoadingCallback callback, final Handler handler)346 public void loadSeriesList(FileInfo parent, final ItemGroupsLoadingCallback callback, final Handler handler) { 347 final FileInfo p = new FileInfo(parent); 348 execTask(new Task("loadSeriesList") { 349 @Override 350 public void work() { 351 mainDB.loadSeriesList(p); 352 sendTask(handler, () -> callback.onItemGroupsLoaded(p)); 353 } 354 }); 355 } 356 loadTitleList(FileInfo parent, final ItemGroupsLoadingCallback callback, final Handler handler)357 public void loadTitleList(FileInfo parent, final ItemGroupsLoadingCallback callback, final Handler handler) { 358 final FileInfo p = new FileInfo(parent); 359 execTask(new Task("loadTitleList") { 360 @Override 361 public void work() { 362 mainDB.loadTitleList(p); 363 sendTask(handler, () -> callback.onItemGroupsLoaded(p)); 364 } 365 }); 366 } 367 findGenresBooks(final String genreCode, boolean showEmptyGenres, final FileInfoLoadingCallback callback, final Handler handler)368 public void findGenresBooks(final String genreCode, boolean showEmptyGenres, final FileInfoLoadingCallback callback, final Handler handler) { 369 execTask(new Task("findGenresBooks") { 370 @Override 371 public void work() { 372 final ArrayList<FileInfo> list = mainDB.findByGenre(genreCode, showEmptyGenres); 373 sendTask(handler, () -> callback.onFileInfoListLoaded(list)); 374 } 375 }); 376 } 377 findAuthorBooks(final long authorId, final FileInfoLoadingCallback callback, final Handler handler)378 public void findAuthorBooks(final long authorId, final FileInfoLoadingCallback callback, final Handler handler) { 379 execTask(new Task("findAuthorBooks") { 380 @Override 381 public void work() { 382 final ArrayList<FileInfo> list = new ArrayList<>(); 383 mainDB.findAuthorBooks(list, authorId); 384 sendTask(handler, () -> callback.onFileInfoListLoaded(list)); 385 } 386 }); 387 } 388 findSeriesBooks(final long seriesId, final FileInfoLoadingCallback callback, final Handler handler)389 public void findSeriesBooks(final long seriesId, final FileInfoLoadingCallback callback, final Handler handler) { 390 execTask(new Task("findSeriesBooks") { 391 @Override 392 public void work() { 393 final ArrayList<FileInfo> list = new ArrayList<>(); 394 mainDB.findSeriesBooks(list, seriesId); 395 sendTask(handler, () -> callback.onFileInfoListLoaded(list)); 396 } 397 }); 398 } 399 findBooksByRating(final int minRate, final int maxRate, final FileInfoLoadingCallback callback, final Handler handler)400 public void findBooksByRating(final int minRate, final int maxRate, final FileInfoLoadingCallback callback, final Handler handler) { 401 execTask(new Task("findBooksByRating") { 402 @Override 403 public void work() { 404 final ArrayList<FileInfo> list = new ArrayList<>(); 405 mainDB.findBooksByRating(list, minRate, maxRate); 406 sendTask(handler, () -> callback.onFileInfoListLoaded(list)); 407 } 408 }); 409 } 410 findBooksByState(final int state, final FileInfoLoadingCallback callback, final Handler handler)411 public void findBooksByState(final int state, final FileInfoLoadingCallback callback, final Handler handler) { 412 execTask(new Task("findBooksByState") { 413 @Override 414 public void work() { 415 final ArrayList<FileInfo> list = new ArrayList<>(); 416 mainDB.findBooksByState(list, state); 417 sendTask(handler, () -> callback.onFileInfoListLoaded(list)); 418 } 419 }); 420 } 421 loadRecentBooks(final int maxCount, final RecentBooksLoadingCallback callback, final Handler handler)422 public void loadRecentBooks(final int maxCount, final RecentBooksLoadingCallback callback, final Handler handler) { 423 execTask(new Task("loadRecentBooks") { 424 @Override 425 public void work() { 426 final ArrayList<BookInfo> list = mainDB.loadRecentBooks(maxCount); 427 sendTask(handler, () -> callback.onRecentBooksListLoaded(list)); 428 } 429 }); 430 } 431 sync(final Runnable callback, final Handler handler)432 public void sync(final Runnable callback, final Handler handler) { 433 execTask(new Task("sync") { 434 @Override 435 public void work() { 436 sendTask(handler, callback); 437 } 438 }); 439 } 440 findByPatterns(final int maxCount, final String authors, final String title, final String series, final String filename, final BookSearchCallback callback, final Handler handler)441 public void findByPatterns(final int maxCount, final String authors, final String title, final String series, final String filename, final BookSearchCallback callback, final Handler handler) { 442 execTask(new Task("findByPatterns") { 443 @Override 444 public void work() { 445 final ArrayList<FileInfo> list = mainDB.findByPatterns(maxCount, authors, title, series, filename); 446 sendTask(handler, () -> callback.onBooksFound(list)); 447 } 448 }); 449 } 450 findByFingerprints(final int maxCount, Collection<String> fingerprints, final BookSearchCallback callback, final Handler handler)451 public void findByFingerprints(final int maxCount, Collection<String> fingerprints, final BookSearchCallback callback, final Handler handler) { 452 execTask(new Task("findByFingerprint") { 453 @Override 454 public void work() { 455 final ArrayList<FileInfo> list = mainDB.findByFingerprints(maxCount, fingerprints); 456 sendTask(handler, () -> callback.onBooksFound(list)); 457 } 458 }); 459 } 460 deepCopyFileInfos(final Collection<FileInfo> src)461 private ArrayList<FileInfo> deepCopyFileInfos(final Collection<FileInfo> src) { 462 final ArrayList<FileInfo> list = new ArrayList<FileInfo>(src.size()); 463 for (FileInfo fi : src) 464 list.add(new FileInfo(fi)); 465 return list; 466 } 467 saveFileInfos(final Collection<FileInfo> list)468 public void saveFileInfos(final Collection<FileInfo> list) { 469 execTask(new Task("saveFileInfos") { 470 @Override 471 public void work() { 472 mainDB.saveFileInfos(list); 473 } 474 }); 475 flush(); 476 } 477 loadBookInfo(final FileInfo fileInfo, final BookInfoLoadingCallback callback, final Handler handler)478 public void loadBookInfo(final FileInfo fileInfo, final BookInfoLoadingCallback callback, final Handler handler) { 479 execTask(new Task("loadBookInfo") { 480 @Override 481 public void work() { 482 final BookInfo bookInfo = mainDB.loadBookInfo(fileInfo); 483 sendTask(handler, () -> callback.onBooksInfoLoaded(bookInfo)); 484 } 485 }); 486 } 487 loadFileInfos(final ArrayList<String> pathNames, final FileInfoLoadingCallback callback, final Handler handler)488 public void loadFileInfos(final ArrayList<String> pathNames, final FileInfoLoadingCallback callback, final Handler handler) { 489 execTask(new Task("loadFileInfos") { 490 @Override 491 public void work() { 492 final ArrayList<FileInfo> list = mainDB.loadFileInfos(pathNames); 493 sendTask(handler, () -> callback.onFileInfoListLoaded(list)); 494 } 495 }); 496 } 497 saveBookInfo(final BookInfo bookInfo)498 public void saveBookInfo(final BookInfo bookInfo) { 499 execTask(new Task("saveBookInfo") { 500 @Override 501 public void work() { 502 mainDB.saveBookInfo(bookInfo); 503 } 504 }); 505 flush(); 506 } 507 deleteBook(final FileInfo fileInfo)508 public void deleteBook(final FileInfo fileInfo) { 509 execTask(new Task("deleteBook") { 510 @Override 511 public void work() { 512 mainDB.deleteBook(fileInfo); 513 coverDB.deleteCoverpage(fileInfo.getPathName()); 514 } 515 }); 516 flush(); 517 } 518 deleteBookmark(final Bookmark bm)519 public void deleteBookmark(final Bookmark bm) { 520 execTask(new Task("deleteBookmark") { 521 @Override 522 public void work() { 523 mainDB.deleteBookmark(bm); 524 } 525 }); 526 flush(); 527 } 528 setPathCorrector(final MountPathCorrector corrector)529 public void setPathCorrector(final MountPathCorrector corrector) { 530 execTask(new Task("setPathCorrector") { 531 @Override 532 public void work() { 533 mainDB.setPathCorrector(corrector); 534 } 535 }); 536 } 537 deleteRecentPosition(final FileInfo fileInfo)538 public void deleteRecentPosition(final FileInfo fileInfo) { 539 execTask(new Task("deleteRecentPosition") { 540 @Override 541 public void work() { 542 mainDB.deleteRecentPosition(fileInfo); 543 } 544 }); 545 flush(); 546 } 547 548 //======================================================================================= 549 // Favorite folders access code 550 //======================================================================================= createFavoriteFolder(final FileInfo folder)551 public void createFavoriteFolder(final FileInfo folder) { 552 execTask(new Task("createFavoriteFolder") { 553 @Override 554 public void work() { 555 mainDB.createFavoritesFolder(folder); 556 } 557 }); 558 flush(); 559 } 560 loadFavoriteFolders(final FileInfoLoadingCallback callback, final Handler handler)561 public void loadFavoriteFolders(final FileInfoLoadingCallback callback, final Handler handler) { 562 execTask(new Task("loadFavoriteFolders") { 563 @Override 564 public void work() { 565 final ArrayList<FileInfo> favorites = mainDB.loadFavoriteFolders(); 566 sendTask(handler, () -> callback.onFileInfoListLoaded(favorites)); 567 } 568 }); 569 } 570 updateFavoriteFolder(final FileInfo folder)571 public void updateFavoriteFolder(final FileInfo folder) { 572 execTask(new Task("updateFavoriteFolder") { 573 @Override 574 public void work() { 575 mainDB.updateFavoriteFolder(folder); 576 } 577 }); 578 flush(); 579 } 580 deleteFavoriteFolder(final FileInfo folder)581 public void deleteFavoriteFolder(final FileInfo folder) { 582 execTask(new Task("deleteFavoriteFolder") { 583 @Override 584 public void work() { 585 mainDB.deleteFavoriteFolder(folder); 586 } 587 }); 588 flush(); 589 } 590 591 private abstract class Task implements Runnable { 592 private final String name; Task(String name)593 public Task(String name) { 594 this.name = name; 595 } 596 597 @Override toString()598 public String toString() { 599 return "Task[" + name + "]"; 600 } 601 602 @Override run()603 public void run() { 604 long ts = Utils.timeStamp(); 605 vlog.v(toString() + " started"); 606 try { 607 work(); 608 } catch (Exception e) { 609 log.e("Exception while running DB task in background", e); 610 } 611 vlog.v(toString() + " finished in " + Utils.timeInterval(ts) + " ms"); 612 } 613 work()614 public abstract void work(); 615 } 616 617 /** 618 * Execute runnable in CDRDBService background thread. 619 * Exceptions will be ignored, just dumped into log. 620 * @param task is Runnable to execute 621 */ execTask(final Task task)622 private void execTask(final Task task) { 623 vlog.v("Posting task " + task); 624 mThread.post(task); 625 } 626 627 /** 628 * Execute runnable in CDRDBService background thread, delayed. 629 * Exceptions will be ignored, just dumped into log. 630 * @param task is Runnable to execute 631 */ execTask(final Task task, long delay)632 private void execTask(final Task task, long delay) { 633 vlog.v("Posting task " + task + " with delay " + delay); 634 mThread.postDelayed(task, delay); 635 } 636 637 /** 638 * Send task to handler, if specified, otherwise run immediately. 639 * Exceptions will be ignored, just dumped into log. 640 * @param handler is handler to send task to, null to run immediately 641 * @param task is Runnable to execute 642 */ sendTask(Handler handler, Runnable task)643 private void sendTask(Handler handler, Runnable task) { 644 try { 645 if (handler != null) { 646 vlog.v("Senging task to " + handler.toString()); 647 handler.post(task); 648 } else { 649 vlog.v("No Handler provided: executing task in current thread"); 650 task.run(); 651 } 652 } catch (Exception e) { 653 log.e("Exception in DB callback", e); 654 } 655 } 656 657 /** 658 * Class for clients to access. Because we know this service always 659 * runs in the same process as its clients, we don't need to deal with 660 * IPC. 661 * Provides interface for asynchronous operations with database. 662 */ 663 public class LocalBinder extends Binder { getService()664 private CRDBService getService() { 665 return CRDBService.this; 666 } 667 saveBookCoverpage(final FileInfo fileInfo, byte[] data)668 public void saveBookCoverpage(final FileInfo fileInfo, byte[] data) { 669 getService().saveBookCoverpage(fileInfo, data); 670 } 671 loadBookCoverpage(final FileInfo fileInfo, final CoverpageLoadingCallback callback)672 public void loadBookCoverpage(final FileInfo fileInfo, final CoverpageLoadingCallback callback) { 673 getService().loadBookCoverpage(new FileInfo(fileInfo), callback, new Handler()); 674 } 675 loadOPDSCatalogs(final OPDSCatalogsLoadingCallback callback)676 public void loadOPDSCatalogs(final OPDSCatalogsLoadingCallback callback) { 677 getService().loadOPDSCatalogs(callback, new Handler()); 678 } 679 saveOPDSCatalog(final Long id, final String url, final String name, final String username, final String password)680 public void saveOPDSCatalog(final Long id, final String url, final String name, final String username, final String password) { 681 getService().saveOPDSCatalog(id, url, name, username, password); 682 } 683 updateOPDSCatalogLastUsage(final String url)684 public void updateOPDSCatalogLastUsage(final String url) { 685 getService().updateOPDSCatalogLastUsage(url); 686 } 687 removeOPDSCatalog(final Long id)688 public void removeOPDSCatalog(final Long id) { 689 getService().removeOPDSCatalog(id); 690 } 691 loadGenresList(FileInfo parent, boolean showEmptyGenres, final ItemGroupsLoadingCallback callback)692 public void loadGenresList(FileInfo parent, boolean showEmptyGenres, final ItemGroupsLoadingCallback callback) { 693 getService().loadGenresList(parent, showEmptyGenres, callback, new Handler()); 694 } 695 loadAuthorsList(FileInfo parent, final ItemGroupsLoadingCallback callback)696 public void loadAuthorsList(FileInfo parent, final ItemGroupsLoadingCallback callback) { 697 getService().loadAuthorsList(parent, callback, new Handler()); 698 } 699 loadSeriesList(FileInfo parent, final ItemGroupsLoadingCallback callback)700 public void loadSeriesList(FileInfo parent, final ItemGroupsLoadingCallback callback) { 701 getService().loadSeriesList(parent, callback, new Handler()); 702 } 703 loadTitleList(FileInfo parent, final ItemGroupsLoadingCallback callback)704 public void loadTitleList(FileInfo parent, final ItemGroupsLoadingCallback callback) { 705 getService().loadTitleList(parent, callback, new Handler()); 706 } 707 loadGenresBooks(String genreCode, boolean showEmptyGenres, FileInfoLoadingCallback callback)708 public void loadGenresBooks(String genreCode, boolean showEmptyGenres, FileInfoLoadingCallback callback) { 709 getService().findGenresBooks(genreCode, showEmptyGenres, callback, new Handler()); 710 } 711 loadAuthorBooks(long authorId, FileInfoLoadingCallback callback)712 public void loadAuthorBooks(long authorId, FileInfoLoadingCallback callback) { 713 getService().findAuthorBooks(authorId, callback, new Handler()); 714 } 715 loadSeriesBooks(long seriesId, FileInfoLoadingCallback callback)716 public void loadSeriesBooks(long seriesId, FileInfoLoadingCallback callback) { 717 getService().findSeriesBooks(seriesId, callback, new Handler()); 718 } 719 loadSearchHistory(BookInfo book, SearchHistoryLoadingCallback callback)720 public void loadSearchHistory(BookInfo book, SearchHistoryLoadingCallback callback) { 721 getService().loadSearchHistory(book, callback, new Handler()); 722 } 723 loadBooksByRating(int minRating, int maxRating, FileInfoLoadingCallback callback)724 public void loadBooksByRating(int minRating, int maxRating, FileInfoLoadingCallback callback) { 725 getService().findBooksByRating(minRating, maxRating, callback, new Handler()); 726 } 727 loadBooksByState(int state, FileInfoLoadingCallback callback)728 public void loadBooksByState(int state, FileInfoLoadingCallback callback) { 729 getService().findBooksByState(state, callback, new Handler()); 730 } 731 loadRecentBooks(final int maxCount, final RecentBooksLoadingCallback callback)732 public void loadRecentBooks(final int maxCount, final RecentBooksLoadingCallback callback) { 733 getService().loadRecentBooks(maxCount, callback, new Handler()); 734 } 735 sync(final Runnable callback)736 public void sync(final Runnable callback) { 737 getService().sync(callback, new Handler()); 738 } 739 saveFileInfos(final Collection<FileInfo> list)740 public void saveFileInfos(final Collection<FileInfo> list) { 741 getService().saveFileInfos(deepCopyFileInfos(list)); 742 } 743 findByFingerprints(final int maxCount, Collection<String> fingerprints, final BookSearchCallback callback)744 public void findByFingerprints(final int maxCount, Collection<String> fingerprints, final BookSearchCallback callback) { 745 getService().findByFingerprints(maxCount, fingerprints, callback, new Handler()); 746 } 747 findByPatterns(final int maxCount, final String authors, final String title, final String series, final String filename, final BookSearchCallback callback)748 public void findByPatterns(final int maxCount, final String authors, final String title, final String series, final String filename, final BookSearchCallback callback) { 749 getService().findByPatterns(maxCount, authors, title, series, filename, callback, new Handler()); 750 } 751 loadFileInfos(final ArrayList<String> pathNames, final FileInfoLoadingCallback callback)752 public void loadFileInfos(final ArrayList<String> pathNames, final FileInfoLoadingCallback callback) { 753 getService().loadFileInfos(pathNames, callback, new Handler()); 754 } 755 deleteBook(final FileInfo fileInfo)756 public void deleteBook(final FileInfo fileInfo) { 757 getService().deleteBook(new FileInfo(fileInfo)); 758 } 759 saveBookInfo(final BookInfo bookInfo)760 public void saveBookInfo(final BookInfo bookInfo) { 761 getService().saveBookInfo(new BookInfo(bookInfo)); 762 } 763 saveSearchHistory(final BookInfo book, String sHist)764 public void saveSearchHistory(final BookInfo book, String sHist) { 765 getService().saveSearchHistory(new BookInfo(book), sHist); 766 } 767 deleteRecentPosition(final FileInfo fileInfo)768 public void deleteRecentPosition(final FileInfo fileInfo) { 769 getService().deleteRecentPosition(new FileInfo(fileInfo)); 770 } 771 deleteBookmark(final Bookmark bm)772 public void deleteBookmark(final Bookmark bm) { 773 getService().deleteBookmark(new Bookmark(bm)); 774 } 775 loadBookInfo(final FileInfo fileInfo, final BookInfoLoadingCallback callback)776 public void loadBookInfo(final FileInfo fileInfo, final BookInfoLoadingCallback callback) { 777 getService().loadBookInfo(new FileInfo(fileInfo), callback, new Handler()); 778 } 779 createFavoriteFolder(final FileInfo folder)780 public void createFavoriteFolder(final FileInfo folder) { 781 getService().createFavoriteFolder(folder); 782 } 783 loadFavoriteFolders(FileInfoLoadingCallback callback)784 public void loadFavoriteFolders(FileInfoLoadingCallback callback) { 785 getService().loadFavoriteFolders(callback, new Handler()); 786 } 787 updateFavoriteFolder(final FileInfo folder)788 public void updateFavoriteFolder(final FileInfo folder) { 789 getService().updateFavoriteFolder(folder); 790 } 791 deleteFavoriteFolder(final FileInfo folder)792 public void deleteFavoriteFolder(final FileInfo folder) { 793 getService().deleteFavoriteFolder(folder); 794 } 795 796 setPathCorrector(MountPathCorrector corrector)797 public void setPathCorrector(MountPathCorrector corrector) { 798 getService().setPathCorrector(corrector); 799 } 800 flush()801 public void flush() { 802 getService().forceFlush(); 803 } 804 reopenDatabase()805 public void reopenDatabase() { 806 getService().reopenDatabase(); 807 } 808 } 809 810 @Override onBind(Intent intent)811 public IBinder onBind(Intent intent) { 812 log.i("onBind(): " + intent); 813 return mBinder; 814 } 815 816 @Override onRebind(Intent intent)817 public void onRebind (Intent intent) { 818 log.i("onRebind(): " + intent); 819 } 820 821 @Override onUnbind(Intent intent)822 public boolean onUnbind(Intent intent) { 823 log.i("onUnbind(): intent=" + intent); 824 return true; 825 } 826 827 private ServiceThread mThread; 828 private final IBinder mBinder = new LocalBinder(); 829 830 } 831