diff --git a/Clover/app/build.gradle b/Clover/app/build.gradle index f9dc9b5f..39a5d4fe 100644 --- a/Clover/app/build.gradle +++ b/Clover/app/build.gradle @@ -1,12 +1,12 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 19 - buildToolsVersion "21.0.2" + compileSdkVersion 21 + buildToolsVersion "21.1.1" defaultConfig { minSdkVersion 14 - targetSdkVersion 19 + targetSdkVersion 21 versionName "v1.2.3" versionCode 41 @@ -70,9 +70,9 @@ dependencies { compile 'org.jsoup:jsoup:1.7.3' compile 'com.j256.ormlite:ormlite-core:4.48' compile 'com.j256.ormlite:ormlite-android:4.48' - compile 'com.android.support:support-v13:18.0.+' - compile 'com.koushikdutta.ion:ion:1.+' - compile 'pl.droidsonroids.gif:android-gif-drawable:1.0.+' + compile 'com.android.support:support-v13:18.0.0' + compile 'com.koushikdutta.ion:ion:1.3.8' + compile 'pl.droidsonroids.gif:android-gif-drawable:1.0.12' compile files('libs/httpclientandroidlib-1.2.1.jar') } diff --git a/Clover/app/proguard.cfg b/Clover/app/proguard.cfg index 4faf19ff..7f3763cc 100644 --- a/Clover/app/proguard.cfg +++ b/Clover/app/proguard.cfg @@ -132,8 +132,3 @@ } -keep public class pl.droidsonroids.gif.GifIOException{*;} - -# Remove these when targetSdkVersion >= 21 --dontwarn pl.droidsonroids.gif.GifImageButton --dontwarn pl.droidsonroids.gif.GifImageView --dontwarn pl.droidsonroids.gif.GifTextView diff --git a/Clover/app/src/main/java/com/davemorrissey/labs/subscaleview/SubsamplingScaleImageView.java b/Clover/app/src/main/java/com/davemorrissey/labs/subscaleview/SubsamplingScaleImageView.java index 72dc5bfa..bb726f2c 100644 --- a/Clover/app/src/main/java/com/davemorrissey/labs/subscaleview/SubsamplingScaleImageView.java +++ b/Clover/app/src/main/java/com/davemorrissey/labs/subscaleview/SubsamplingScaleImageView.java @@ -1028,6 +1028,10 @@ public class SubsamplingScaleImageView extends View { } catch (OutOfMemoryError e) { Log.e(TAG, "OOM in decode tile", e); System.gc(); + final SubsamplingScaleImageView view = viewRef.get(); + if (view != null) { + view.onOutOfMemory(); + } } return null; } @@ -1092,6 +1096,10 @@ public class SubsamplingScaleImageView extends View { } catch (OutOfMemoryError e) { Log.e(TAG, "OOM in decode tile", e); System.gc(); + final SubsamplingScaleImageView view = viewRef.get(); + if (view != null) { + view.onOutOfMemory(); + } } return null; } @@ -1538,6 +1546,10 @@ public class SubsamplingScaleImageView extends View { } + protected void onOutOfMemory() { + + } + /** * Call to find whether the view is initialised and ready for rendering tiles. */ diff --git a/Clover/app/src/main/java/org/floens/chan/core/ChanPreferences.java b/Clover/app/src/main/java/org/floens/chan/core/ChanPreferences.java index 69790391..4de9c150 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/ChanPreferences.java +++ b/Clover/app/src/main/java/org/floens/chan/core/ChanPreferences.java @@ -37,10 +37,6 @@ public class ChanPreferences { return p().getString("preference_default_name", ""); } - public static String getDefaultEmail() { - return p().getString("preference_default_email", ""); - } - public static boolean getPinOnPost() { return p().getBoolean("preference_pin_on_post", false); } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/activity/ChanActivity.java b/Clover/app/src/main/java/org/floens/chan/ui/activity/ChanActivity.java index 695ed96a..b74360ba 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/activity/ChanActivity.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/activity/ChanActivity.java @@ -105,8 +105,9 @@ public class ChanActivity extends BaseActivity implements AdapterView.OnItemSele Uri startUri = startIntent.getData(); if (savedInstanceState != null) { - threadLoadable.readFromBundle(this, "thread", savedInstanceState); - startLoadingThread(threadLoadable); + Loadable threadTmp = new Loadable(); + threadTmp.readFromBundle(this, "thread", savedInstanceState); + startLoadingThread(threadTmp); // Reset page etc. Loadable tmp = new Loadable(); @@ -649,9 +650,6 @@ public class ChanActivity extends BaseActivity implements AdapterView.OnItemSele } private class BoardSpinnerAdapter extends BaseAdapter { - private static final int VIEW_TYPE_ITEM = 0; - private static final int VIEW_TYPE_ADD = 1; - private Context context; private Spinner spinner; private List boards; @@ -699,16 +697,6 @@ public class ChanActivity extends BaseActivity implements AdapterView.OnItemSele return boards.size() + 1; } - @Override - public int getViewTypeCount() { - return 2; - } - - @Override - public int getItemViewType(int position) { - return position == getCount() - 1 ? VIEW_TYPE_ADD : VIEW_TYPE_ITEM; - } - @Override public long getItemId(final int position) { return position; @@ -716,42 +704,24 @@ public class ChanActivity extends BaseActivity implements AdapterView.OnItemSele @Override public String getItem(final int position) { - switch (getItemViewType(position)) { - case VIEW_TYPE_ITEM: - return boards.get(position).key; - case VIEW_TYPE_ADD: - return context.getString(R.string.board_select_add); - default: - return ""; + if (position == getCount() - 1) { + return context.getString(R.string.board_select_add); + } else { + return boards.get(position).key; } } @Override public View getView(final int position, View convertView, final ViewGroup parent) { - switch (getItemViewType(position)) { - case VIEW_TYPE_ITEM: { - if (convertView == null || (Integer) convertView.getTag() != VIEW_TYPE_ITEM) { - convertView = LayoutInflater.from(context).inflate(R.layout.board_select_spinner, null); - convertView.setTag(VIEW_TYPE_ITEM); - } - - TextView textView = (TextView) convertView; - textView.setText(getItem(position)); - return textView; - } - case VIEW_TYPE_ADD: { - if (convertView == null || (Integer) convertView.getTag() != VIEW_TYPE_ADD) { - convertView = LayoutInflater.from(context).inflate(R.layout.board_select_add, null); - convertView.setTag(VIEW_TYPE_ADD); - } - - TextView textView = (TextView) convertView; - textView.setText(getItem(position)); - return textView; - } + if (position == getCount() - 1) { + TextView textView = (TextView) LayoutInflater.from(context).inflate(R.layout.board_select_add, null); + textView.setText(getItem(position)); + return textView; + } else { + TextView textView = (TextView) LayoutInflater.from(context).inflate(R.layout.board_select_spinner, null); + textView.setText(getItem(position)); + return textView; } - - return null; } } } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/activity/ImageViewActivity.java b/Clover/app/src/main/java/org/floens/chan/ui/activity/ImageViewActivity.java index 8081fc24..bc425855 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/activity/ImageViewActivity.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/activity/ImageViewActivity.java @@ -266,7 +266,9 @@ public class ImageViewActivity extends Activity implements ViewPager.OnPageChang } private ImageViewFragment getFragment(int i) { - if (i >= 0 && i < adapter.getCount()) { + if (adapter == null) { + return null; + } else if (i >= 0 && i < adapter.getCount()) { Object o = adapter.instantiateItem(viewPager, i); if (o instanceof ImageViewFragment) { return (ImageViewFragment) o; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/fragment/ReplyFragment.java b/Clover/app/src/main/java/org/floens/chan/ui/fragment/ReplyFragment.java index 61b0a052..9a223eae 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/fragment/ReplyFragment.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/fragment/ReplyFragment.java @@ -165,10 +165,6 @@ public class ReplyFragment extends DialogFragment { draft.name = ChanPreferences.getDefaultName(); } - if (TextUtils.isEmpty(draft.email)) { - draft.email = ChanPreferences.getDefaultEmail(); - } - nameView.setText(draft.name); emailView.setText(draft.email); subjectView.setText(draft.subject); @@ -383,7 +379,7 @@ public class ReplyFragment extends DialogFragment { private void closeReply() { if (getDialog() != null) { - dismiss(); + dismissAllowingStateLoss(); } else { context.finish(); } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/fragment/ThreadFragment.java b/Clover/app/src/main/java/org/floens/chan/ui/fragment/ThreadFragment.java index 35ca2383..975a5c2a 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/fragment/ThreadFragment.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/fragment/ThreadFragment.java @@ -19,7 +19,6 @@ package org.floens.chan.ui.fragment; import android.app.Fragment; import android.content.Context; -import android.content.Intent; import android.content.res.TypedArray; import android.os.Bundle; import android.util.AttributeSet; @@ -61,7 +60,6 @@ import org.floens.chan.utils.Utils; import javax.net.ssl.SSLException; public class ThreadFragment extends Fragment implements ThreadManager.ThreadManagerListener, PostAdapter.PostAdapterListener { - private BaseActivity baseActivity; private ThreadManager threadManager; private Loadable loadable; @@ -78,7 +76,6 @@ public class ThreadFragment extends Fragment implements ThreadManager.ThreadMana public static ThreadFragment newInstance(BaseActivity activity) { ThreadFragment fragment = new ThreadFragment(); - fragment.baseActivity = activity; fragment.threadManager = new ThreadManager(activity, fragment); return fragment; @@ -171,13 +168,17 @@ public class ThreadFragment extends Fragment implements ThreadManager.ThreadMana @Override public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) { container = new LoadView(inflater.getContext()); + if (loadable == null) { + container.setView(getCenteredMessageView(R.string.thread_not_specified)); + } + return container; } @Override public void onPostClicked(Post post) { if (loadable.isBoardMode() || loadable.isCatalogMode()) { - baseActivity.onOPClicked(post); + ((BaseActivity) getActivity()).onOPClicked(post); } else if (loadable.isThreadMode() && isFiltering) { filterView.clearSearch(); postAdapter.scrollToPost(post.no); @@ -187,7 +188,7 @@ public class ThreadFragment extends Fragment implements ThreadManager.ThreadMana @Override public void onThumbnailClicked(Post source) { if (postAdapter != null) { - ImageViewActivity.launch(baseActivity, postAdapter, source.no, threadManager); + ImageViewActivity.launch(getActivity(), postAdapter, source.no, threadManager); } } @@ -207,7 +208,7 @@ public class ThreadFragment extends Fragment implements ThreadManager.ThreadMana @Override public void onOpenThread(final Loadable thread, int highlightedPost) { - baseActivity.onOpenThread(thread); + ((BaseActivity) getActivity()).onOpenThread(thread); this.highlightedPost = highlightedPost; } @@ -233,7 +234,7 @@ public class ThreadFragment extends Fragment implements ThreadManager.ThreadMana highlightedPost = -1; } - baseActivity.onThreadLoaded(thread); + ((BaseActivity) getActivity()).onThreadLoaded(thread); } @Override @@ -262,25 +263,25 @@ public class ThreadFragment extends Fragment implements ThreadManager.ThreadMana } private RelativeLayout createView() { - RelativeLayout compound = new RelativeLayout(baseActivity); + RelativeLayout compound = new RelativeLayout(getActivity()); - LinearLayout listViewContainer = new LinearLayout(baseActivity); + LinearLayout listViewContainer = new LinearLayout(getActivity()); listViewContainer.setOrientation(LinearLayout.VERTICAL); - filterView = new FilterView(baseActivity); + filterView = new FilterView(getActivity()); filterView.setVisibility(View.GONE); listViewContainer.addView(filterView, Utils.MATCH_WRAP_PARAMS); if (viewMode == ThreadManager.ViewMode.LIST) { - ListView list = new ListView(baseActivity); + ListView list = new ListView(getActivity()); listView = list; - postAdapter = new PostAdapter(baseActivity, threadManager, listView, this); + postAdapter = new PostAdapter(getActivity(), threadManager, listView, this); listView.setAdapter(postAdapter); list.setSelectionFromTop(loadable.listViewIndex, loadable.listViewTop); } else if (viewMode == ThreadManager.ViewMode.GRID) { - GridView grid = new GridView(baseActivity); + GridView grid = new GridView(getActivity()); grid.setNumColumns(GridView.AUTO_FIT); - TypedArray ta = baseActivity.obtainStyledAttributes(null, R.styleable.PostView, R.attr.post_style, 0); + TypedArray ta = getActivity().obtainStyledAttributes(null, R.styleable.PostView, R.attr.post_style, 0); int postGridWidth = ta.getDimensionPixelSize(R.styleable.PostView_grid_width, 0); int postGridSpacing = ta.getDimensionPixelSize(R.styleable.PostView_grid_spacing, 0); ta.recycle(); @@ -288,7 +289,7 @@ public class ThreadFragment extends Fragment implements ThreadManager.ThreadMana grid.setVerticalSpacing(postGridSpacing); grid.setHorizontalSpacing(postGridSpacing); listView = grid; - postAdapter = new PostAdapter(baseActivity, threadManager, listView, this); + postAdapter = new PostAdapter(getActivity(), threadManager, listView, this); listView.setAdapter(postAdapter); listView.setSelection(loadable.listViewIndex); } @@ -327,7 +328,7 @@ public class ThreadFragment extends Fragment implements ThreadManager.ThreadMana compound.addView(listViewContainer, Utils.MATCH_PARAMS); if (loadable.isThreadMode()) { - skip = new ImageView(baseActivity); + skip = new ImageView(getActivity()); skip.setImageResource(R.drawable.skip_arrow_down); skip.setVisibility(View.GONE); compound.addView(skip, Utils.WRAP_PARAMS); @@ -376,7 +377,7 @@ public class ThreadFragment extends Fragment implements ThreadManager.ThreadMana private View getLoadErrorView(VolleyError error) { String errorMessage = getLoadErrorText(error); - LinearLayout wrapper = new LinearLayout(baseActivity); + LinearLayout wrapper = new LinearLayout(getActivity()); wrapper.setLayoutParams(Utils.MATCH_PARAMS); wrapper.setGravity(Gravity.CENTER); wrapper.setOrientation(LinearLayout.VERTICAL); @@ -387,7 +388,7 @@ public class ThreadFragment extends Fragment implements ThreadManager.ThreadMana text.setTextSize(24f); wrapper.addView(text); - Button retry = new Button(baseActivity); + Button retry = new Button(getActivity()); retry.setText(R.string.thread_load_failed_retry); retry.setLayoutParams(Utils.WRAP_PARAMS); retry.setGravity(Gravity.CENTER); @@ -425,6 +426,16 @@ public class ThreadFragment extends Fragment implements ThreadManager.ThreadMana return errorMessage; } + private View getCenteredMessageView(int stringResourceId) { + LinearLayout layout = new LinearLayout(getActivity()); + layout.setGravity(Gravity.CENTER); + TextView messageView = new TextView(getActivity()); + messageView.setText(getString(stringResourceId)); + layout.addView(messageView); + + return layout; + } + private static class SkipLogic { private final ImageView skip; private int lastFirstVisibleItem; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/view/CustomScaleImageView.java b/Clover/app/src/main/java/org/floens/chan/ui/view/CustomScaleImageView.java index 89980d73..a21c81c1 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/view/CustomScaleImageView.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/view/CustomScaleImageView.java @@ -20,6 +20,8 @@ import android.util.AttributeSet; import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView; +import org.floens.chan.utils.Utils; + public class CustomScaleImageView extends SubsamplingScaleImageView { private InitedCallback initCallback; @@ -39,12 +41,33 @@ public class CustomScaleImageView extends SubsamplingScaleImageView { protected void onImageReady() { super.onImageReady(); - if (initCallback != null) { - initCallback.onInit(); - } + Utils.runOnUiThread(new Runnable() { + @Override + public void run() { + if (initCallback != null) { + initCallback.onInit(); + } + } + }); + } + + @Override + protected void onOutOfMemory() { + super.onOutOfMemory(); + + Utils.runOnUiThread(new Runnable() { + @Override + public void run() { + if (initCallback != null) { + initCallback.onOutOfMemory(); + } + } + }); } public interface InitedCallback { public void onInit(); + + public void onOutOfMemory(); } } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/view/ThumbnailImageView.java b/Clover/app/src/main/java/org/floens/chan/ui/view/ThumbnailImageView.java index a2864ff3..fd9945da 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/view/ThumbnailImageView.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/view/ThumbnailImageView.java @@ -19,6 +19,7 @@ package org.floens.chan.ui.view; import android.content.ActivityNotFoundException; import android.content.Context; +import android.content.ContextWrapper; import android.content.Intent; import android.media.MediaPlayer; import android.net.Uri; @@ -157,14 +158,14 @@ public class ThumbnailImageView extends LoadView implements View.OnClickListener image.setInitCallback(new CustomScaleImageView.InitedCallback() { @Override public void onInit() { - Utils.runOnUiThread(new Runnable() { - @Override - public void run() { - removeAllViews(); - addView(image); - callback.setProgress(false); - } - }); + removeAllViews(); + addView(image); + callback.setProgress(false); + } + + @Override + public void onOutOfMemory() { + onOutOfMemoryError(); } }); } @@ -212,6 +213,11 @@ public class ThumbnailImageView extends LoadView implements View.OnClickListener e.printStackTrace(); onError(); return; + } catch (OutOfMemoryError e) { + System.gc(); + e.printStackTrace(); + onOutOfMemoryError(); + return; } GifImageView view = new GifImageView(getContext()); @@ -261,7 +267,9 @@ public class ThumbnailImageView extends LoadView implements View.OnClickListener Toast.makeText(getContext(), R.string.open_link_failed, Toast.LENGTH_SHORT).show(); } } else { - videoView = new VideoView(getContext()); + Context proxyContext = new NoMusicServiceCommandContext(getContext()); + + videoView = new VideoView(proxyContext); videoView.setZOrderOnTop(true); videoView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); @@ -299,7 +307,7 @@ public class ThumbnailImageView extends LoadView implements View.OnClickListener } public void onError() { - Toast.makeText(getContext(), R.string.image_preview_failed, Toast.LENGTH_LONG).show(); + Toast.makeText(getContext(), R.string.image_preview_failed, Toast.LENGTH_SHORT).show(); callback.setProgress(false); } @@ -308,6 +316,11 @@ public class ThumbnailImageView extends LoadView implements View.OnClickListener callback.setProgress(false); } + public void onOutOfMemoryError() { + Toast.makeText(getContext(), R.string.image_preview_failed_oom, Toast.LENGTH_SHORT).show(); + callback.setProgress(false); + } + public void cancelLoad() { if (imageRequest != null) { imageRequest.cancel(); @@ -335,4 +348,19 @@ public class ThumbnailImageView extends LoadView implements View.OnClickListener public void onVideoError(File video); } + + public static class NoMusicServiceCommandContext extends ContextWrapper { + public NoMusicServiceCommandContext(Context base) { + super(base); + } + + @Override + public void sendBroadcast(Intent intent) { + // Only allow broadcasts when it's not a music service command + // Prevents pause intents from broadcasting + if (!"com.android.music.musicservicecommand".equals(intent.getAction())) { + super.sendBroadcast(intent); + } + } + } } diff --git a/Clover/app/src/main/res/values/strings.xml b/Clover/app/src/main/res/values/strings.xml index f49c4344..8f5513db 100644 --- a/Clover/app/src/main/res/values/strings.xml +++ b/Clover/app/src/main/res/values/strings.xml @@ -61,6 +61,7 @@ along with this program. If not, see . Start / stop playing Failed to show image + Failed to show image, out of memory Image not found Failed to open image @@ -71,6 +72,7 @@ along with this program. If not, see . Server inaccessible 404 not found No more posts + Select a thread Tap to refresh Loading Loading in %1$d diff --git a/Clover/app/src/main/res/xml/preference.xml b/Clover/app/src/main/res/xml/preference.xml index 27532113..44599fd5 100644 --- a/Clover/app/src/main/res/xml/preference.xml +++ b/Clover/app/src/main/res/xml/preference.xml @@ -91,9 +91,6 @@ along with this program. If not, see . -