From c3ef26505d08de09ac67279d178502bee35b81fe Mon Sep 17 00:00:00 2001 From: Miku Nyan Date: Thu, 21 Apr 2016 19:54:50 +0300 Subject: [PATCH] move gallery to separate process --- .classpath | 6 +- AndroidManifest.xml | 6 +- .../wishmaster/common/MainApplication.java | 19 + .../ui/{ => gallery}/GalleryActivity.java | 389 ++++++----------- .../ui/gallery/GalleryAttachmentInfo.aidl | 21 + .../ui/gallery/GalleryAttachmentInfo.java | 75 ++++ .../wishmaster/ui/gallery/GalleryBackend.java | 402 ++++++++++++++++++ .../wishmaster/ui/gallery/GalleryBinder.aidl | 35 ++ .../ui/{ => gallery}/GalleryFullscreen.java | 3 +- .../ui/gallery/GalleryGetterCallback.aidl | 34 ++ .../ui/gallery/GalleryInitData.aidl | 21 + .../ui/gallery/GalleryInitData.java | 81 ++++ .../ui/gallery/GalleryInitResult.aidl | 21 + .../ui/gallery/GalleryInitResult.java | 99 +++++ .../GalleryInteractiveExceptionHolder.aidl | 21 + .../GalleryInteractiveExceptionHolder.java | 58 +++ .../wishmaster/ui/gallery/GalleryRemote.java | 89 ++++ .../ui/presentation/BoardFragment.java | 2 +- 18 files changed, 1124 insertions(+), 258 deletions(-) rename src/nya/miku/wishmaster/ui/{ => gallery}/GalleryActivity.java (78%) create mode 100644 src/nya/miku/wishmaster/ui/gallery/GalleryAttachmentInfo.aidl create mode 100644 src/nya/miku/wishmaster/ui/gallery/GalleryAttachmentInfo.java create mode 100644 src/nya/miku/wishmaster/ui/gallery/GalleryBackend.java create mode 100644 src/nya/miku/wishmaster/ui/gallery/GalleryBinder.aidl rename src/nya/miku/wishmaster/ui/{ => gallery}/GalleryFullscreen.java (98%) create mode 100644 src/nya/miku/wishmaster/ui/gallery/GalleryGetterCallback.aidl create mode 100644 src/nya/miku/wishmaster/ui/gallery/GalleryInitData.aidl create mode 100644 src/nya/miku/wishmaster/ui/gallery/GalleryInitData.java create mode 100644 src/nya/miku/wishmaster/ui/gallery/GalleryInitResult.aidl create mode 100644 src/nya/miku/wishmaster/ui/gallery/GalleryInitResult.java create mode 100644 src/nya/miku/wishmaster/ui/gallery/GalleryInteractiveExceptionHolder.aidl create mode 100644 src/nya/miku/wishmaster/ui/gallery/GalleryInteractiveExceptionHolder.java create mode 100644 src/nya/miku/wishmaster/ui/gallery/GalleryRemote.java diff --git a/.classpath b/.classpath index 7bc01d9a9..279373fed 100644 --- a/.classpath +++ b/.classpath @@ -1,7 +1,11 @@ - + + + + + diff --git a/AndroidManifest.xml b/AndroidManifest.xml index c32813ca1..d17ffbd67 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -203,9 +203,10 @@ along with this program. If not, see . android:configChanges="keyboardHidden|orientation|screenSize" /> + android:theme="@style/Transparent" + android:process=":Gallery" /> . + diff --git a/src/nya/miku/wishmaster/common/MainApplication.java b/src/nya/miku/wishmaster/common/MainApplication.java index cccd597ab..e692e38f0 100644 --- a/src/nya/miku/wishmaster/common/MainApplication.java +++ b/src/nya/miku/wishmaster/common/MainApplication.java @@ -48,6 +48,8 @@ import org.acra.ACRA; import org.acra.annotation.ReportsCrashes; +import android.app.ActivityManager; +import android.app.ActivityManager.RunningAppProcessInfo; import android.app.Application; import android.content.SharedPreferences; import android.content.res.Resources; @@ -245,10 +247,27 @@ private File getAvailableCacheDir() { return externalCacheDir != null ? externalCacheDir : getCacheDir(); } + private String getProcessName() { + int myPid = android.os.Process.myPid(); + for (RunningAppProcessInfo process : ((ActivityManager) getSystemService(ACTIVITY_SERVICE)).getRunningAppProcesses()) { + if (myPid == process.pid) return process.processName; + } + return null; + } + + private boolean isGalleryProcess() { + try { + return getProcessName().endsWith(":Gallery"); + } catch (Exception e) { + return false; + } + } + @Override public void onCreate() { super.onCreate(); if (ACRAConstants.ACRA_ENABLED) ACRA.init(this); + if (isGalleryProcess()) return; initObjects(); instance = this; } diff --git a/src/nya/miku/wishmaster/ui/GalleryActivity.java b/src/nya/miku/wishmaster/ui/gallery/GalleryActivity.java similarity index 78% rename from src/nya/miku/wishmaster/ui/GalleryActivity.java rename to src/nya/miku/wishmaster/ui/gallery/GalleryActivity.java index a52664b62..8863265f5 100644 --- a/src/nya/miku/wishmaster/ui/GalleryActivity.java +++ b/src/nya/miku/wishmaster/ui/gallery/GalleryActivity.java @@ -16,14 +16,10 @@ * along with this program. If not, see . */ -package nya.miku.wishmaster.ui; +package nya.miku.wishmaster.ui.gallery; import java.io.File; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.io.OutputStream; import java.lang.ref.WeakReference; -import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.Timer; @@ -34,21 +30,12 @@ import org.apache.commons.lang3.tuple.Triple; import nya.miku.wishmaster.R; -import nya.miku.wishmaster.api.ChanModule; import nya.miku.wishmaster.api.interfaces.CancellableTask; import nya.miku.wishmaster.api.interfaces.ProgressListener; import nya.miku.wishmaster.api.models.AttachmentModel; import nya.miku.wishmaster.api.models.BoardModel; -import nya.miku.wishmaster.api.models.UrlPageModel; -import nya.miku.wishmaster.api.util.ChanModels; -import nya.miku.wishmaster.cache.BitmapCache; -import nya.miku.wishmaster.cache.FileCache; import nya.miku.wishmaster.common.Async; -import nya.miku.wishmaster.common.IOUtils; import nya.miku.wishmaster.common.Logger; -import nya.miku.wishmaster.common.MainApplication; -import nya.miku.wishmaster.containers.ReadableContainer; -import nya.miku.wishmaster.http.interactive.InteractiveException; import nya.miku.wishmaster.lib.gallery.FixedSubsamplingScaleImageView; import nya.miku.wishmaster.lib.gallery.JSWebView; import nya.miku.wishmaster.lib.gallery.Jpeg; @@ -56,23 +43,22 @@ import nya.miku.wishmaster.lib.gallery.WebViewFixed; import nya.miku.wishmaster.lib.gallery.verticalviewpager.VerticalViewPagerFixed; import nya.miku.wishmaster.lib.gifdrawable.GifDrawable; -import nya.miku.wishmaster.ui.downloading.DownloadingLocker; +import nya.miku.wishmaster.ui.AppearanceUtils; +import nya.miku.wishmaster.ui.Attachments; +import nya.miku.wishmaster.ui.CompatibilityImpl; import nya.miku.wishmaster.ui.downloading.DownloadingService; import nya.miku.wishmaster.ui.presentation.BoardFragment; -import nya.miku.wishmaster.ui.presentation.PresentationModel; import nya.miku.wishmaster.ui.settings.ApplicationSettings; -import nya.miku.wishmaster.ui.tabs.TabModel; -import nya.miku.wishmaster.ui.tabs.TabsState; -import nya.miku.wishmaster.ui.tabs.TabsSwitcher; import nya.miku.wishmaster.ui.tabs.UrlHandler; import nya.miku.wishmaster.ui.theme.ThemeUtils; +import android.annotation.SuppressLint; import android.app.Activity; -import android.app.ProgressDialog; import android.content.BroadcastReceiver; +import android.content.ComponentName; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; +import android.content.ServiceConnection; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; @@ -82,7 +68,10 @@ import android.os.Build; import android.os.Bundle; import android.os.Handler; +import android.os.IBinder; import android.os.Message; +import android.os.RemoteException; +import android.preference.PreferenceManager; import android.support.v4.view.MotionEventCompat; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; @@ -118,13 +107,14 @@ public class GalleryActivity extends Activity implements View.OnClickListener { public static final String EXTRA_PAGEHASH = "pagehash"; public static final String EXTRA_LOCALFILENAME = "localfilename"; - private DownloadingLocker downloadingLocker; + @SuppressLint("InlinedApi") + private static final int BINDING_FLAGS = Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT; + private LayoutInflater inflater; - private CancellableTask tnDownloadingTask; private ExecutorService tnDownloadingExecutor; private BoardModel boardModel; - private ReadableContainer localFile; + private String chan; private ProgressBar progressBar; private ViewPager viewPager; @@ -132,17 +122,14 @@ public class GalleryActivity extends Activity implements View.OnClickListener { private SparseArray instantiatedViews; private BroadcastReceiver broadcastReceiver; + private ServiceConnection serviceConnection; + private GalleryRemote remote; - private ChanModule chan; private ApplicationSettings settings; - private FileCache fileCache; - private BitmapCache bitmapCache; private List> attachments = null; private int currentPosition = 0; private int previousPosition = -1; - private String customSubdir = null; - private boolean firstScroll = true; private Menu menu; @@ -198,90 +185,40 @@ private void hideProgress() { progressListener.setProgress(1); } + private abstract class AbstractGetterCallback extends GalleryGetterCallback.Stub { + private final CancellableTask task; + public AbstractGetterCallback(CancellableTask task) { + this.task = task; + } + @Override + public boolean isTaskCancelled() throws RemoteException { + return task.isCancelled(); + } + @Override + public void setProgress(long value) throws RemoteException { + progressListener.setProgress(value); + } + @Override + public void setProgressIndeterminate() throws RemoteException { + progressListener.setIndeterminate(); + } + @Override + public void setProgressMaxValue(long value) throws RemoteException { + progressListener.setMaxValue(value); + } + } + @Override - protected void onCreate(Bundle savedInstanceState) { + protected void onCreate(final Bundle savedInstanceState) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) requestWindowFeature(Window.FEATURE_PROGRESS); - settings = MainApplication.getInstance().settings; + settings = new ApplicationSettings(PreferenceManager.getDefaultSharedPreferences(getApplication()), getResources()); settings.getTheme().setTo(this, R.style.Transparent); - super.onCreate(savedInstanceState); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) CompatibilityImpl.setActionBarNoIcon(this); - downloadingLocker = MainApplication.getInstance().downloadingLocker; inflater = getLayoutInflater(); instantiatedViews = new SparseArray(); - tnDownloadingTask = new CancellableTask.BaseCancellableTask(); tnDownloadingExecutor = Executors.newFixedThreadPool(4, Async.LOW_PRIORITY_FACTORY); - fileCache = MainApplication.getInstance().fileCache; - bitmapCache = MainApplication.getInstance().bitmapCache; - - AttachmentModel attachment = (AttachmentModel) getIntent().getSerializableExtra(EXTRA_ATTACHMENT); - boardModel = (BoardModel) getIntent().getSerializableExtra(EXTRA_BOARDMODEL); - if (boardModel == null) return; - String pagehash = getIntent().getStringExtra(EXTRA_PAGEHASH); - String localFilename = getIntent().getStringExtra(EXTRA_LOCALFILENAME); - if (localFilename != null) { - try { - localFile = ReadableContainer.obtain(new File(localFilename)); - } catch (Exception e) { - Logger.e(TAG, "cannot open local file", e); - } - } - - chan = MainApplication.getInstance().getChanModule(boardModel.chan); - PresentationModel presentationModel = MainApplication.getInstance().pagesCache.getPresentationModel(pagehash); - if (presentationModel != null) { - boolean isThread = presentationModel.source.pageModel.type == UrlPageModel.TYPE_THREADPAGE; - customSubdir = BoardFragment.getCustomSubdir(presentationModel.source.pageModel); - List> list = presentationModel.getAttachments(); - presentationModel = null; - if (list != null) { - int index = -1; - String attachmentHash = getIntent().getStringExtra(EXTRA_SAVED_ATTACHMENTHASH); - if (attachmentHash == null) attachmentHash = ChanModels.hashAttachmentModel(attachment); - for (int i=0; i 0 && list.get(--it).getRight().equals(threadNumber)) ++leftOffset; - it = index; while (it < (list.size()-1) && list.get(++it).getRight().equals(threadNumber)) ++rightOffset; - attachments = list.subList(index - leftOffset, index + rightOffset + 1); - currentPosition = leftOffset; - } - } - } - } else /* if (presentationModel == null) */ { - final String savedHash = savedInstanceState != null ? savedInstanceState.getString(EXTRA_SAVED_ATTACHMENTHASH) : null; - if (savedHash != null) registerReceiver(new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (intent.getAction() != null && intent.getAction().equals(BoardFragment.BROADCAST_PAGE_LOADED)) { - unregisterReceiver(this); - broadcastReceiver = null; - - Intent activityIntent = getIntent(); - String pagehash = activityIntent.getStringExtra(EXTRA_PAGEHASH); - if (pagehash != null && MainApplication.getInstance().pagesCache.getPresentationModel(pagehash) != null) { - startActivity(activityIntent.putExtra(EXTRA_SAVED_ATTACHMENTHASH, savedHash)); - finish(); - } - } - } - }, new IntentFilter(BoardFragment.BROADCAST_PAGE_LOADED)); - } - if (attachments == null) { - attachments = Collections.singletonList(Triple.of(attachment, ChanModels.hashAttachmentModel(attachment), (String)null)); - currentPosition = 0; - } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH && settings.fullscreenGallery()) { setContentView(R.layout.gallery_layout_fullscreen); @@ -289,20 +226,51 @@ public void onReceive(Context context, Intent intent) { } else { setContentView(R.layout.gallery_layout); } + progressBar = (ProgressBar) findViewById(android.R.id.progress); progressBar.setMax(Window.PROGRESS_END); viewPager = (ViewPager) findViewById(R.id.gallery_viewpager); navigationInfo = (TextView) findViewById(R.id.gallery_navigation_info); for (int id : new int[] { R.id.gallery_navigation_previous, R.id.gallery_navigation_next }) findViewById(id).setOnClickListener(this); - viewPager.setAdapter(new GalleryAdapter()); - viewPager.setCurrentItem(currentPosition); - viewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { + + bindService(new Intent(this, GalleryBackend.class), new ServiceConnection() { + { serviceConnection = this; } + @Override - public void onPageSelected(int position) { - currentPosition = position; - updateItem(); + public void onServiceConnected(ComponentName name, IBinder service) { + GalleryBinder galleryBinder = GalleryBinder.Stub.asInterface(service); + try { + GalleryInitData initData = new GalleryInitData(getIntent(), savedInstanceState); + boardModel = initData.boardModel; + chan = boardModel.chan; + GalleryInitResult init = galleryBinder.initContext(initData); + remote = new GalleryRemote(galleryBinder, init.contextId); + attachments = init.attachments; + currentPosition = init.initPosition; + if (init.shouldWaitForPageLoaded) waitForPageLoaded(savedInstanceState); + + viewPager.setAdapter(new GalleryAdapter()); + viewPager.setCurrentItem(currentPosition); + viewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { + @Override + public void onPageSelected(int position) { + currentPosition = position; + updateItem(); + } + }); + } catch (Exception e) { + Logger.e(TAG, e); + finish(); + } } - }); + + @Override + public void onServiceDisconnected(ComponentName name) { + Logger.e(TAG, "backend service disconnected"); + remote = null; + System.exit(0); + } + }, BINDING_FLAGS); } @Override @@ -311,6 +279,26 @@ protected void onSaveInstanceState(Bundle outState) { outState.putString(EXTRA_SAVED_ATTACHMENTHASH, attachments.get(currentPosition).getMiddle()); } + private void waitForPageLoaded(Bundle savedInstanceState) { + final String savedHash = savedInstanceState != null ? savedInstanceState.getString(EXTRA_SAVED_ATTACHMENTHASH) : null; + if (savedHash != null) registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction() != null && intent.getAction().equals(BoardFragment.BROADCAST_PAGE_LOADED)) { + unregisterReceiver(this); + broadcastReceiver = null; + + Intent activityIntent = getIntent(); + String pagehash = activityIntent.getStringExtra(EXTRA_PAGEHASH); + if (pagehash != null && remote.isPageLoaded(pagehash)) { + startActivity(activityIntent.putExtra(EXTRA_SAVED_ATTACHMENTHASH, savedHash)); + finish(); + } + } + } + }, new IntentFilter(BoardFragment.BROADCAST_PAGE_LOADED)); + } + @Override protected void onStop() { super.onStop(); @@ -321,7 +309,6 @@ protected void onStop() { @Override protected void onDestroy() { super.onDestroy(); - if (tnDownloadingTask != null) tnDownloadingTask.cancel(); if (instantiatedViews != null) { for (int i=0; i + * + * 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 3 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, see . + */ + +package nya.miku.wishmaster.ui.gallery; + +parcelable GalleryAttachmentInfo; \ No newline at end of file diff --git a/src/nya/miku/wishmaster/ui/gallery/GalleryAttachmentInfo.java b/src/nya/miku/wishmaster/ui/gallery/GalleryAttachmentInfo.java new file mode 100644 index 000000000..a8824244f --- /dev/null +++ b/src/nya/miku/wishmaster/ui/gallery/GalleryAttachmentInfo.java @@ -0,0 +1,75 @@ +/* + * Overchan Android (Meta Imageboard Client) + * Copyright (C) 2014-2016 miku-nyan + * + * 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 3 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, see . + */ + +package nya.miku.wishmaster.ui.gallery; + +import android.os.Parcel; +import android.os.Parcelable; +import nya.miku.wishmaster.api.models.AttachmentModel; + +public class GalleryAttachmentInfo implements Parcelable { + public AttachmentModel attachment; + public String hash; + + public GalleryAttachmentInfo(AttachmentModel attachment, String hash) { + this.attachment = attachment; + this.hash = hash; + } + + public GalleryAttachmentInfo(Parcel parcel) { + hash = parcel.readString(); + attachment = new AttachmentModel(); + attachment.type = parcel.readInt(); + attachment.size = parcel.readInt(); + attachment.thumbnail = parcel.readString(); + attachment.path = parcel.readString(); + attachment.width = parcel.readInt(); + attachment.height = parcel.readInt(); + attachment.originalName = parcel.readString(); + attachment.isSpoiler = parcel.readInt() == 1; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeString(hash); + parcel.writeInt(attachment.type); + parcel.writeInt(attachment.size); + parcel.writeString(attachment.thumbnail); + parcel.writeString(attachment.path); + parcel.writeInt(attachment.width); + parcel.writeInt(attachment.height); + parcel.writeString(attachment.originalName); + parcel.writeInt(attachment.isSpoiler ? 1 : 0); + } + + @Override + public int describeContents() { + return 0; + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public GalleryAttachmentInfo createFromParcel(Parcel in) { + return new GalleryAttachmentInfo(in); + } + + public GalleryAttachmentInfo[] newArray(int size) { + return new GalleryAttachmentInfo[size]; + } + }; + +} diff --git a/src/nya/miku/wishmaster/ui/gallery/GalleryBackend.java b/src/nya/miku/wishmaster/ui/gallery/GalleryBackend.java new file mode 100644 index 000000000..16e28f298 --- /dev/null +++ b/src/nya/miku/wishmaster/ui/gallery/GalleryBackend.java @@ -0,0 +1,402 @@ +/* + * Overchan Android (Meta Imageboard Client) + * Copyright (C) 2014-2016 miku-nyan + * + * 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 3 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, see . + */ + +package nya.miku.wishmaster.ui.gallery; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; + +import org.apache.commons.lang3.tuple.Triple; + +import android.app.Service; +import android.content.Intent; +import android.graphics.Bitmap; +import android.os.IBinder; +import android.os.RemoteException; +import nya.miku.wishmaster.R; +import nya.miku.wishmaster.api.ChanModule; +import nya.miku.wishmaster.api.interfaces.CancellableTask; +import nya.miku.wishmaster.api.interfaces.ProgressListener; +import nya.miku.wishmaster.api.models.AttachmentModel; +import nya.miku.wishmaster.api.models.BoardModel; +import nya.miku.wishmaster.api.models.UrlPageModel; +import nya.miku.wishmaster.api.util.ChanModels; +import nya.miku.wishmaster.cache.BitmapCache; +import nya.miku.wishmaster.cache.FileCache; +import nya.miku.wishmaster.common.Async; +import nya.miku.wishmaster.common.IOUtils; +import nya.miku.wishmaster.common.Logger; +import nya.miku.wishmaster.common.MainApplication; +import nya.miku.wishmaster.containers.ReadableContainer; +import nya.miku.wishmaster.http.interactive.InteractiveException; +import nya.miku.wishmaster.ui.Attachments; +import nya.miku.wishmaster.ui.downloading.DownloadingLocker; +import nya.miku.wishmaster.ui.downloading.DownloadingService; +import nya.miku.wishmaster.ui.presentation.BoardFragment; +import nya.miku.wishmaster.ui.presentation.PresentationModel; +import nya.miku.wishmaster.ui.settings.ApplicationSettings; +import nya.miku.wishmaster.ui.tabs.TabModel; +import nya.miku.wishmaster.ui.tabs.TabsState; +import nya.miku.wishmaster.ui.tabs.TabsSwitcher; + +public class GalleryBackend extends Service { + private static final String TAG = "GalleryBackend"; + + private IBinder binder; + + private ApplicationSettings settings; + private DownloadingLocker downloadingLocker; + private CancellableTask tnDownloadingTask; + private FileCache fileCache; + private BitmapCache bitmapCache; + private List contexts; + + @Override + public void onCreate() { + super.onCreate(); + settings = MainApplication.getInstance().settings; + downloadingLocker = MainApplication.getInstance().downloadingLocker; + tnDownloadingTask = new CancellableTask.BaseCancellableTask(); + fileCache = MainApplication.getInstance().fileCache; + bitmapCache = MainApplication.getInstance().bitmapCache; + contexts = new ArrayList<>(); + binder = new MyBinder().asBinder(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (tnDownloadingTask != null) tnDownloadingTask.cancel(); + for (GalleryContext context : contexts) { + if (context.localFile != null) { + try { + context.localFile.close(); + } catch (Exception e) { + Logger.e(TAG, "cannot close local file", e); + } + } + } + } + + @Override + public IBinder onBind(Intent intent) { + return binder; + } + + private class MyBinder extends GalleryBinder.Stub { + @Override + public boolean isPageLoaded(String pagehash) { + return MainApplication.getInstance().pagesCache.getPresentationModel(pagehash) != null; + } + + @Override + public GalleryInitResult initContext(GalleryInitData initData) { + GalleryContext context = new GalleryContext(); + GalleryInitResult result = context.init(initData); + synchronized (contexts) { + result.contextId = contexts.size(); + contexts.add(context); + } + return result; + } + + @Override + public Bitmap getBitmapFromMemory(int contextId, String hash) { + return contexts.get(contextId).getBitmapFromMemory(hash); + } + + @Override + public Bitmap getBitmap(int contextId, String hash, String url) { + return contexts.get(contextId).getBitmap(hash, url); + } + + @Override + public String getAttachment(int contextId, GalleryAttachmentInfo attachment, GalleryGetterCallback callback) { + try { + File file = contexts.get(contextId).getFile(attachment.hash, attachment.attachment, callback); + return file.getPath(); + } catch (Exception e) { + Logger.e(TAG, e); + return null; + } + } + + @Override + public String getAbsoluteUrl(int contextId, String url) { + return contexts.get(contextId).getAbsoluteUrl(url); + } + + @Override + public void tryScrollParent(int contextId, String postNumber) { + contexts.get(contextId).tryScrollParent(postNumber); + } + } + + private class GalleryContext { + private ChanModule chan; + private String customSubdir; + private BoardModel boardModel; + private ReadableContainer localFile; + + public GalleryInitResult init(GalleryInitData initData) { + GalleryInitResult result = new GalleryInitResult(); + boardModel = initData.boardModel; + chan = MainApplication.getInstance().getChanModule(boardModel.chan); + + if (initData.localFileName != null) { + try { + localFile = ReadableContainer.obtain(new File(initData.localFileName)); + } catch (Exception e) { + Logger.e(TAG, "cannot open local file", e); + } + } + + PresentationModel presentationModel = MainApplication.getInstance().pagesCache.getPresentationModel(initData.pageHash); + if (presentationModel != null) { + boolean isThread = presentationModel.source.pageModel.type == UrlPageModel.TYPE_THREADPAGE; + this.customSubdir = BoardFragment.getCustomSubdir(presentationModel.source.pageModel); + List> attachments = presentationModel.getAttachments(); + presentationModel = null; + + if (attachments != null) { + List> list = attachments; + + int index = -1; + String attachmentHash = initData.attachmentHash; + for (int i=0; i 0 && list.get(--it).getRight().equals(threadNumber)) ++leftOffset; + it = index; while (it < (list.size()-1) && list.get(++it).getRight().equals(threadNumber)) ++rightOffset; + result.attachments = list.subList(index - leftOffset, index + rightOffset + 1); + result.initPosition = leftOffset; + } + } + } + } else { + result.shouldWaitForPageLoaded = true; + } + + if (result.attachments == null) { + result.attachments = Collections.singletonList( + Triple.of(initData.attachment, ChanModels.hashAttachmentModel(initData.attachment), (String)null)); + result.initPosition = 0; + } + return result; + } + + public Bitmap getBitmapFromMemory(String hash) { + return bitmapCache.getFromMemory(hash); + } + + public Bitmap getBitmap(String hash, String url) { + Bitmap bmp = bitmapCache.getFromCache(hash); + if (bmp == null && localFile != null) { + bmp = bitmapCache.getFromContainer(hash, localFile); + } + if (bmp == null && url != null && url.length() != 0) { + bmp = bitmapCache.download(hash, url, getResources().getDimensionPixelSize(R.dimen.post_thumbnail_size), chan, tnDownloadingTask); + } + return bmp; + } + + public File getFile(String attachmentHash, AttachmentModel attachmentModel, GalleryGetterCallback callback) throws RemoteException { + AsyncCallback asyncCallback = new AsyncCallback(callback); + try { + Async.runAsync(asyncCallback); + return getFile(attachmentHash, attachmentModel, asyncCallback); + } finally { + asyncCallback.stop(); + } + } + + public File getFile(String attachmentHash, AttachmentModel attachmentModel, final AsyncCallback callback) throws RemoteException { + File file = fileCache.get(FileCache.PREFIX_ORIGINALS + attachmentHash + Attachments.getAttachmentExtention(attachmentModel)); + if (file != null) { + String filename = file.getAbsolutePath(); + while (downloadingLocker.isLocked(filename)) downloadingLocker.waitUnlock(filename); + if (callback.isCancelled()) return null; + } + if (file == null || !file.exists() || file.isDirectory() || file.length() == 0) { + File dir = new File(settings.getDownloadDirectory(), chan.getChanName()); + file = new File(dir, Attachments.getAttachmentLocalFileName(attachmentModel, boardModel)); + String filename = file.getAbsolutePath(); + while (downloadingLocker.isLocked(filename)) downloadingLocker.waitUnlock(filename); + if (callback.isCancelled()) return null; + } + if (customSubdir != null) { + if (file == null || !file.exists() || file.isDirectory() || file.length() == 0) { + File dir = new File(settings.getDownloadDirectory(), chan.getChanName()); + dir = new File(dir, customSubdir); + file = new File(dir, Attachments.getAttachmentLocalFileName(attachmentModel, boardModel)); + String filename = file.getAbsolutePath(); + while (downloadingLocker.isLocked(filename)) downloadingLocker.waitUnlock(filename); + if (callback.isCancelled()) return null; + } + } + if (!file.exists() || file.isDirectory() || file.length() == 0) { + callback.getCallback().showLoading(); + file = fileCache.create(FileCache.PREFIX_ORIGINALS + attachmentHash + Attachments.getAttachmentExtention(attachmentModel)); + String filename = file.getAbsolutePath(); + while (!downloadingLocker.lock(filename)) downloadingLocker.waitUnlock(filename); + InputStream fromLocal = null; + OutputStream out = null; + boolean success = false; + try { + out = new FileOutputStream(file); + String localName = DownloadingService.ORIGINALS_FOLDER + "/" + + Attachments.getAttachmentLocalFileName(attachmentModel, boardModel); + if (localFile != null && localFile.hasFile(localName)) { + fromLocal = IOUtils.modifyInputStream(localFile.openStream(localName), null, callback); + IOUtils.copyStream(fromLocal, out); + } else { + chan.downloadFile(attachmentModel.path, out, callback, callback); + } + fileCache.put(file); + success = true; + } catch (final Exception e) { + if (callback.isCancelled()) return null; + if (e instanceof InteractiveException) { + callback.getCallback().onInteractiveException(new GalleryInteractiveExceptionHolder((InteractiveException) e)); + } else if (IOUtils.isENOSPC(e)) { + callback.getCallback().onException(getString(R.string.error_no_space)); + } else { + callback.getCallback().onException(e.getMessage()); + } + return null; + } finally { + IOUtils.closeQuietly(fromLocal); + IOUtils.closeQuietly(out); + if (file != null && !success) file.delete(); + downloadingLocker.unlock(filename); + } + } + return file; + } + + public String getAbsoluteUrl(String url) { + return chan.fixRelativeUrl(url); + } + + public void tryScrollParent(final String postNumber) { + try { + TabsState tabsState = MainApplication.getInstance().tabsState; + final TabsSwitcher tabsSwitcher = MainApplication.getInstance().tabsSwitcher; + if (tabsSwitcher.currentFragment instanceof BoardFragment) { + TabModel tab = tabsState.findTabById(tabsSwitcher.currentId); + if (tab != null && tab.pageModel != null && tab.pageModel.type == UrlPageModel.TYPE_THREADPAGE) { + Async.runOnUiThread(new Runnable() { + @Override + public void run() { + ((BoardFragment) tabsSwitcher.currentFragment).scrollToItem(postNumber); + } + }); + } + } + } catch (Exception e) { + Logger.e(TAG, e); + } + } + } + + public static class AsyncCallback implements ProgressListener, CancellableTask, Runnable { + private final static long DELAY = 50; + + private final GalleryGetterCallback callback; + private final AtomicLong progress, maxValue; + private final AtomicBoolean indeterminate, taskCancelled; + + private volatile boolean working = true; + + public AsyncCallback(GalleryGetterCallback callback) { + this.callback = callback; + this.progress = new AtomicLong(Long.MIN_VALUE); + this.maxValue = new AtomicLong(Long.MIN_VALUE); + this.indeterminate = new AtomicBoolean(false); + this.taskCancelled = new AtomicBoolean(false); + } + + public GalleryGetterCallback getCallback() { + return callback; + } + + @Override + public void setMaxValue(long value) { + maxValue.set(value); + } + + @Override + public void setProgress(long value) { + progress.set(value); + } + + @Override + public void setIndeterminate() { + indeterminate.set(true); + } + + @Override + public boolean isCancelled() { + return taskCancelled.get(); + } + + @Override + public void run() { + while (working) { + try { + long curProgress = progress.getAndSet(Long.MIN_VALUE); + long curMaxValue = maxValue.getAndSet(Long.MIN_VALUE); + boolean curIndeterminate = indeterminate.getAndSet(false); + if (callback.isTaskCancelled()) taskCancelled.set(true); + if (curProgress != Long.MIN_VALUE) callback.setProgress(curProgress); + if (curMaxValue != Long.MIN_VALUE) callback.setProgressMaxValue(curMaxValue); + if (curIndeterminate) callback.setProgressIndeterminate(); + Thread.sleep(DELAY); + } catch (Exception e) { + Logger.e(TAG, e); + } + } + } + + public void stop() { + working = false; + } + + @Override + public void cancel() { + throw new UnsupportedOperationException(); + } + } +} diff --git a/src/nya/miku/wishmaster/ui/gallery/GalleryBinder.aidl b/src/nya/miku/wishmaster/ui/gallery/GalleryBinder.aidl new file mode 100644 index 000000000..6e7472eba --- /dev/null +++ b/src/nya/miku/wishmaster/ui/gallery/GalleryBinder.aidl @@ -0,0 +1,35 @@ +/* + * Overchan Android (Meta Imageboard Client) + * Copyright (C) 2014-2016 miku-nyan + * + * 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 3 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, see . + */ + +package nya.miku.wishmaster.ui.gallery; + +import android.graphics.Bitmap; +import nya.miku.wishmaster.ui.gallery.GalleryAttachmentInfo; +import nya.miku.wishmaster.ui.gallery.GalleryGetterCallback; +import nya.miku.wishmaster.ui.gallery.GalleryInitData; +import nya.miku.wishmaster.ui.gallery.GalleryInitResult; + +interface GalleryBinder { + GalleryInitResult initContext(in GalleryInitData initData); + Bitmap getBitmapFromMemory(int contextId, String hash); + Bitmap getBitmap(int contextId, String hash, String url); + String getAttachment(int contextId, in GalleryAttachmentInfo attachment, GalleryGetterCallback callback); + String getAbsoluteUrl(int contextId, String url); + void tryScrollParent(int contextId, String postNumber); + boolean isPageLoaded(String pagehash); +} \ No newline at end of file diff --git a/src/nya/miku/wishmaster/ui/GalleryFullscreen.java b/src/nya/miku/wishmaster/ui/gallery/GalleryFullscreen.java similarity index 98% rename from src/nya/miku/wishmaster/ui/GalleryFullscreen.java rename to src/nya/miku/wishmaster/ui/gallery/GalleryFullscreen.java index 19cf9a0f9..af3e2a862 100644 --- a/src/nya/miku/wishmaster/ui/GalleryFullscreen.java +++ b/src/nya/miku/wishmaster/ui/gallery/GalleryFullscreen.java @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -package nya.miku.wishmaster.ui; +package nya.miku.wishmaster.ui.gallery; import android.annotation.SuppressLint; import android.annotation.TargetApi; @@ -32,6 +32,7 @@ import android.view.WindowManager; import nya.miku.wishmaster.R; import nya.miku.wishmaster.common.Async; +import nya.miku.wishmaster.ui.AppearanceUtils; import nya.miku.wishmaster.ui.theme.ThemeUtils; public class GalleryFullscreen { diff --git a/src/nya/miku/wishmaster/ui/gallery/GalleryGetterCallback.aidl b/src/nya/miku/wishmaster/ui/gallery/GalleryGetterCallback.aidl new file mode 100644 index 000000000..f30b19544 --- /dev/null +++ b/src/nya/miku/wishmaster/ui/gallery/GalleryGetterCallback.aidl @@ -0,0 +1,34 @@ +/* + * Overchan Android (Meta Imageboard Client) + * Copyright (C) 2014-2016 miku-nyan + * + * 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 3 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, see . + */ + +package nya.miku.wishmaster.ui.gallery; + +import nya.miku.wishmaster.ui.gallery.GalleryInteractiveExceptionHolder; + +interface GalleryGetterCallback { + boolean isTaskCancelled(); + + void showLoading(); + + void setProgressMaxValue(long value); + void setProgress(long value); + void setProgressIndeterminate(); + + void onException(String message); + void onInteractiveException(in GalleryInteractiveExceptionHolder holder); +} \ No newline at end of file diff --git a/src/nya/miku/wishmaster/ui/gallery/GalleryInitData.aidl b/src/nya/miku/wishmaster/ui/gallery/GalleryInitData.aidl new file mode 100644 index 000000000..5ade0777c --- /dev/null +++ b/src/nya/miku/wishmaster/ui/gallery/GalleryInitData.aidl @@ -0,0 +1,21 @@ +/* + * Overchan Android (Meta Imageboard Client) + * Copyright (C) 2014-2016 miku-nyan + * + * 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 3 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, see . + */ + +package nya.miku.wishmaster.ui.gallery; + +parcelable GalleryInitData; \ No newline at end of file diff --git a/src/nya/miku/wishmaster/ui/gallery/GalleryInitData.java b/src/nya/miku/wishmaster/ui/gallery/GalleryInitData.java new file mode 100644 index 000000000..65cd9b4ce --- /dev/null +++ b/src/nya/miku/wishmaster/ui/gallery/GalleryInitData.java @@ -0,0 +1,81 @@ +/* + * Overchan Android (Meta Imageboard Client) + * Copyright (C) 2014-2016 miku-nyan + * + * 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 3 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, see . + */ + +package nya.miku.wishmaster.ui.gallery; + +import android.content.Intent; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; +import nya.miku.wishmaster.api.models.AttachmentModel; +import nya.miku.wishmaster.api.models.BoardModel; +import nya.miku.wishmaster.api.util.ChanModels; + +public class GalleryInitData implements Parcelable { + public AttachmentModel attachment; + public String attachmentHash; + public BoardModel boardModel; + public String pageHash; + public String localFileName; + + public GalleryInitData(Intent intent, Bundle bundle) { + attachment = (AttachmentModel) intent.getSerializableExtra(GalleryActivity.EXTRA_ATTACHMENT); + boardModel = (BoardModel) intent.getSerializableExtra(GalleryActivity.EXTRA_BOARDMODEL); + if (boardModel == null) throw new NullPointerException(); + pageHash = intent.getStringExtra(GalleryActivity.EXTRA_PAGEHASH); + localFileName = intent.getStringExtra(GalleryActivity.EXTRA_LOCALFILENAME); + attachmentHash = intent.getStringExtra(GalleryActivity.EXTRA_SAVED_ATTACHMENTHASH); + if (attachmentHash == null && bundle != null) attachmentHash = bundle.getString(GalleryActivity.EXTRA_SAVED_ATTACHMENTHASH); + if (attachmentHash == null) attachmentHash = ChanModels.hashAttachmentModel(attachment); + } + + public GalleryInitData(Parcel parcel) { + attachment = (AttachmentModel) parcel.readSerializable(); + attachmentHash = parcel.readString(); + boardModel = (BoardModel) parcel.readSerializable(); + pageHash = parcel.readString(); + localFileName = parcel.readString(); + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeSerializable(attachment); + dest.writeString(attachmentHash); + dest.writeSerializable(boardModel); + dest.writeString(pageHash); + dest.writeString(localFileName); + } + + @Override + public int describeContents() { + return 0; + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override + public GalleryInitData createFromParcel(Parcel source) { + return new GalleryInitData(source); + } + + @Override + public GalleryInitData[] newArray(int size) { + return new GalleryInitData[size]; + } + }; + +} diff --git a/src/nya/miku/wishmaster/ui/gallery/GalleryInitResult.aidl b/src/nya/miku/wishmaster/ui/gallery/GalleryInitResult.aidl new file mode 100644 index 000000000..31bbe58db --- /dev/null +++ b/src/nya/miku/wishmaster/ui/gallery/GalleryInitResult.aidl @@ -0,0 +1,21 @@ +/* + * Overchan Android (Meta Imageboard Client) + * Copyright (C) 2014-2016 miku-nyan + * + * 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 3 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, see . + */ + +package nya.miku.wishmaster.ui.gallery; + +parcelable GalleryInitResult; \ No newline at end of file diff --git a/src/nya/miku/wishmaster/ui/gallery/GalleryInitResult.java b/src/nya/miku/wishmaster/ui/gallery/GalleryInitResult.java new file mode 100644 index 000000000..d415cd0af --- /dev/null +++ b/src/nya/miku/wishmaster/ui/gallery/GalleryInitResult.java @@ -0,0 +1,99 @@ +/* + * Overchan Android (Meta Imageboard Client) + * Copyright (C) 2014-2016 miku-nyan + * + * 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 3 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, see . + */ + +package nya.miku.wishmaster.ui.gallery; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang3.tuple.Triple; + +import android.os.Parcel; +import android.os.Parcelable; +import nya.miku.wishmaster.api.models.AttachmentModel; + +public class GalleryInitResult implements Parcelable { + public int contextId; + public List> attachments; + public int initPosition; + public boolean shouldWaitForPageLoaded; + + public GalleryInitResult() { + } + + public GalleryInitResult(Parcel parcel) { + contextId = parcel.readInt(); + initPosition = parcel.readInt(); + shouldWaitForPageLoaded = parcel.readInt() == 1; + int n = parcel.readInt(); + attachments = new ArrayList<>(n); + for (int i=0; i tuple : attachments) { + AttachmentModel attachment = tuple.getLeft(); + dest.writeInt(attachment.type); + dest.writeInt(attachment.size); + dest.writeString(attachment.thumbnail); + dest.writeString(attachment.path); + dest.writeInt(attachment.width); + dest.writeInt(attachment.height); + dest.writeString(attachment.originalName); + dest.writeInt(attachment.isSpoiler ? 1 : 0); + dest.writeString(tuple.getMiddle()); + dest.writeString(tuple.getRight()); + } + } + + @Override + public int describeContents() { + return 0; + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override + public GalleryInitResult createFromParcel(Parcel source) { + return new GalleryInitResult(source); + } + + @Override + public GalleryInitResult[] newArray(int size) { + return new GalleryInitResult[size]; + } + }; + +} diff --git a/src/nya/miku/wishmaster/ui/gallery/GalleryInteractiveExceptionHolder.aidl b/src/nya/miku/wishmaster/ui/gallery/GalleryInteractiveExceptionHolder.aidl new file mode 100644 index 000000000..106ff5410 --- /dev/null +++ b/src/nya/miku/wishmaster/ui/gallery/GalleryInteractiveExceptionHolder.aidl @@ -0,0 +1,21 @@ +/* + * Overchan Android (Meta Imageboard Client) + * Copyright (C) 2014-2016 miku-nyan + * + * 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 3 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, see . + */ + +package nya.miku.wishmaster.ui.gallery; + +parcelable GalleryInteractiveExceptionHolder; \ No newline at end of file diff --git a/src/nya/miku/wishmaster/ui/gallery/GalleryInteractiveExceptionHolder.java b/src/nya/miku/wishmaster/ui/gallery/GalleryInteractiveExceptionHolder.java new file mode 100644 index 000000000..ab9bd0436 --- /dev/null +++ b/src/nya/miku/wishmaster/ui/gallery/GalleryInteractiveExceptionHolder.java @@ -0,0 +1,58 @@ +/* + * Overchan Android (Meta Imageboard Client) + * Copyright (C) 2014-2016 miku-nyan + * + * 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 3 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, see . + */ + +package nya.miku.wishmaster.ui.gallery; + +import android.os.Parcel; +import android.os.Parcelable; +import nya.miku.wishmaster.http.interactive.InteractiveException; + +public class GalleryInteractiveExceptionHolder implements Parcelable { + public final InteractiveException e; + + public GalleryInteractiveExceptionHolder(InteractiveException e) { + this.e = e; + } + + public GalleryInteractiveExceptionHolder(Parcel parcel) { + e = (InteractiveException) parcel.readSerializable(); + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeSerializable(e); + } + + @Override + public int describeContents() { + return 0; + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override + public GalleryInteractiveExceptionHolder createFromParcel(Parcel source) { + return new GalleryInteractiveExceptionHolder(source); + } + + @Override + public GalleryInteractiveExceptionHolder[] newArray(int size) { + return new GalleryInteractiveExceptionHolder[size]; + } + }; + +} diff --git a/src/nya/miku/wishmaster/ui/gallery/GalleryRemote.java b/src/nya/miku/wishmaster/ui/gallery/GalleryRemote.java new file mode 100644 index 000000000..50bae4435 --- /dev/null +++ b/src/nya/miku/wishmaster/ui/gallery/GalleryRemote.java @@ -0,0 +1,89 @@ +/* + * Overchan Android (Meta Imageboard Client) + * Copyright (C) 2014-2016 miku-nyan + * + * 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 3 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, see . + */ + +package nya.miku.wishmaster.ui.gallery; + +import java.io.File; + +import android.graphics.Bitmap; +import nya.miku.wishmaster.common.Logger; + +public class GalleryRemote { + private static final String TAG = "GalleryContextBinder"; + + public final GalleryBinder binder; + public final int contextId; + + public GalleryRemote(GalleryBinder binder, int contextId) { + this.binder = binder; + this.contextId = contextId; + } + + public boolean isPageLoaded(String pagehash) { + try { + return binder.isPageLoaded(pagehash); + } catch (Exception e) { + Logger.e(TAG, e); + return false; + } + } + + public Bitmap getBitmapFromMemory(String hash) { + try { + return binder.getBitmapFromMemory(contextId, hash); + } catch (Exception e) { + Logger.e(TAG, e); + return null; + } + } + + public Bitmap getBitmap(String hash, String url) { + try { + return binder.getBitmap(contextId, hash, url); + } catch (Exception e) { + Logger.e(TAG, e); + return null; + } + } + + public File getAttachment(GalleryAttachmentInfo attachment, GalleryGetterCallback callback) { + try { + return new File(binder.getAttachment(contextId, attachment, callback)); + } catch (Exception e) { + Logger.e(TAG, e); + return null; + } + } + + public String getAbsoluteUrl(String url) { + try { + return binder.getAbsoluteUrl(contextId, url); + } catch (Exception e) { + Logger.e(TAG, e); + return null; + } + } + + public void tryScrollParent(String postNumber) { + try { + binder.tryScrollParent(contextId, postNumber); + } catch (Exception e) { + Logger.e(TAG, e); + } + } +} diff --git a/src/nya/miku/wishmaster/ui/presentation/BoardFragment.java b/src/nya/miku/wishmaster/ui/presentation/BoardFragment.java index d3c5bb0ec..8367f598b 100644 --- a/src/nya/miku/wishmaster/ui/presentation/BoardFragment.java +++ b/src/nya/miku/wishmaster/ui/presentation/BoardFragment.java @@ -62,11 +62,11 @@ import nya.miku.wishmaster.ui.Clipboard; import nya.miku.wishmaster.ui.CompatibilityImpl; import nya.miku.wishmaster.ui.Database; -import nya.miku.wishmaster.ui.GalleryActivity; import nya.miku.wishmaster.ui.MainActivity; import nya.miku.wishmaster.ui.QuickAccess; import nya.miku.wishmaster.ui.CompatibilityUtils; import nya.miku.wishmaster.ui.downloading.DownloadingService; +import nya.miku.wishmaster.ui.gallery.GalleryActivity; import nya.miku.wishmaster.ui.downloading.BackgroundThumbDownloader; import nya.miku.wishmaster.ui.posting.PostFormActivity; import nya.miku.wishmaster.ui.posting.PostingService;