diff --git a/app/src/main/java/org/schabi/newpipe/fragments/search/SearchWorker.java b/app/src/main/java/org/schabi/newpipe/fragments/search/SearchWorker.java deleted file mode 100644 index 582df9950..000000000 --- a/app/src/main/java/org/schabi/newpipe/fragments/search/SearchWorker.java +++ /dev/null @@ -1,216 +0,0 @@ -package org.schabi.newpipe.fragments.search; - -import android.app.Activity; -import android.content.SharedPreferences; -import android.os.Handler; -import android.preference.PreferenceManager; -import android.util.Log; -import android.view.View; - -import org.schabi.newpipe.R; -import org.schabi.newpipe.extractor.NewPipe; -import org.schabi.newpipe.extractor.exceptions.ExtractionException; -import org.schabi.newpipe.extractor.exceptions.ReCaptchaException; -import org.schabi.newpipe.extractor.search.SearchEngine; -import org.schabi.newpipe.extractor.search.SearchResult; -import org.schabi.newpipe.report.ErrorActivity; - -import java.io.IOException; -import java.util.EnumSet; - -/** - * Created by Christian Schabesberger on 02.08.16. - * - * Copyright (C) Christian Schabesberger 2016 - * SearchWorker.java is part of NewPipe. - * - * NewPipe 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. - * - * NewPipe 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 NewPipe. If not, see . - */ - - -public class SearchWorker { - private static final String TAG = SearchWorker.class.toString(); - - public interface SearchWorkerResultListener { - void onResult(SearchResult result); - void onNothingFound(final int stringResource); - void onError(String message); - void onReCaptchaChallenge(); - } - - private class ResultRunnable implements Runnable { - private final SearchResult result; - private int requestId = 0; - public ResultRunnable(SearchResult result, int requestId) { - this.result = result; - this.requestId = requestId; - } - @Override - public void run() { - if(this.requestId == SearchWorker.this.requestId) { - searchWorkerResultListener.onResult(result); - } - } - } - - private class SearchRunnable implements Runnable { - public static final String YOUTUBE = "Youtube"; - private final String query; - private final int page; - private final EnumSet filter; - final Handler h = new Handler(); - private volatile boolean runs = true; - private Activity a = null; - private int serviceId = -1; - public SearchRunnable(int serviceId, - String query, - int page, - EnumSet filter, - Activity activity, - int requestId) { - this.serviceId = serviceId; - this.query = query; - this.page = page; - this.filter = filter; - this.a = activity; - } - void terminate() { - runs = false; - } - @Override - public void run() { - final String serviceName = NewPipe.getNameOfService(serviceId); - SearchResult result = null; - SearchEngine engine = null; - - try { - engine = NewPipe.getService(serviceId) - .getSearchEngineInstance(); - } catch(ExtractionException e) { - ErrorActivity.reportError(h, a, e, null, null, - ErrorActivity.ErrorInfo.make(ErrorActivity.SEARCHED, - Integer.toString(serviceId), query, R.string.general_error)); - return; - } - - try { - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(a); - String searchLanguageKey = a.getString(R.string.search_language_key); - String searchLanguage = sp.getString(searchLanguageKey, - a.getString(R.string.default_language_value)); - result = SearchResult - .getSearchResult(engine, query, page, searchLanguage, filter); - if(runs) { - h.post(new ResultRunnable(result, requestId)); - } - - // look for errors during extraction - // soft errors: - View rootView = a.findViewById(android.R.id.content); - if(result != null && - !result.errors.isEmpty()) { - Log.e(TAG, "OCCURRED ERRORS DURING SEARCH EXTRACTION:"); - for(Throwable e : result.errors) { - e.printStackTrace(); - Log.e(TAG, "------"); - } - - if(result.resultList.isEmpty()&& !result.errors.isEmpty()) { - // if it compleatly failes dont show snackbar, instead show error directlry - ErrorActivity.reportError(h, a, result.errors, null, null, - ErrorActivity.ErrorInfo.make(ErrorActivity.SEARCHED, - serviceName, query, R.string.parsing_error)); - } else { - // if it partly show snackbar - ErrorActivity.reportError(h, a, result.errors, null, rootView, - ErrorActivity.ErrorInfo.make(ErrorActivity.SEARCHED, - serviceName, query, R.string.light_parsing_error)); - } - } - // hard errors: - } catch (ReCaptchaException e) { - h.post(new Runnable() { - @Override - public void run() { - searchWorkerResultListener.onReCaptchaChallenge(); - } - }); - } catch(IOException e) { - h.post(new Runnable() { - @Override - public void run() { - searchWorkerResultListener.onNothingFound(R.string.network_error); - } - }); - e.printStackTrace(); - } catch(final SearchEngine.NothingFoundException e) { - h.post(new Runnable() { - @Override - public void run() { - searchWorkerResultListener.onError(e.getMessage()); - } - }); - } catch(ExtractionException e) { - ErrorActivity.reportError(h, a, e, null, null, - ErrorActivity.ErrorInfo.make(ErrorActivity.SEARCHED, - serviceName, query, R.string.parsing_error)); - //postNewErrorToast(h, R.string.parsing_error); - e.printStackTrace(); - - } catch(Exception e) { - ErrorActivity.reportError(h, a, e, null, null, - ErrorActivity.ErrorInfo.make(ErrorActivity.SEARCHED, - /* todo: this shoudl not be assigned static */ YOUTUBE, query, R.string.general_error)); - - e.printStackTrace(); - } - } - } - - private static SearchWorker searchWorker = null; - private SearchWorkerResultListener searchWorkerResultListener = null; - private SearchRunnable runnable = null; - private int requestId = 0; //prevents running requests that have already ben expired - - public static SearchWorker getInstance() { - return searchWorker == null ? (searchWorker = new SearchWorker()) : searchWorker; - } - - public void setSearchWorkerResultListener(SearchWorkerResultListener listener) { - searchWorkerResultListener = listener; - } - - private SearchWorker() { - - } - - public void search(int serviceId, - String query, - int page, - Activity a, - EnumSet filter) { - if(runnable != null) { - terminate(); - } - runnable = new SearchRunnable(serviceId, query, page, filter, a, requestId); - Thread thread = new Thread(runnable); - thread.start(); - } - - public void terminate() { - if (runnable == null) return; - requestId++; - runnable.terminate(); - } -} diff --git a/app/src/main/java/org/schabi/newpipe/fragments/search/SuggestionSearchRunnable.java b/app/src/main/java/org/schabi/newpipe/fragments/search/SuggestionSearchRunnable.java deleted file mode 100644 index 10800c7e3..000000000 --- a/app/src/main/java/org/schabi/newpipe/fragments/search/SuggestionSearchRunnable.java +++ /dev/null @@ -1,105 +0,0 @@ -package org.schabi.newpipe.fragments.search; - -import android.app.Activity; -import android.content.SharedPreferences; -import android.os.Handler; -import android.preference.PreferenceManager; -import android.widget.Toast; - -import org.schabi.newpipe.R; -import org.schabi.newpipe.extractor.NewPipe; -import org.schabi.newpipe.extractor.SuggestionExtractor; -import org.schabi.newpipe.extractor.exceptions.ExtractionException; -import org.schabi.newpipe.report.ErrorActivity; - -import java.io.IOException; -import java.util.List; - -/** - * Created by Christian Schabesberger on 02.08.16. - * - * Copyright (C) Christian Schabesberger 2016 - * SuggestionSearchRunnable.java is part of NewPipe. - * - * NewPipe 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. - * - * NewPipe 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 NewPipe. If not, see . - */ - -public class SuggestionSearchRunnable implements Runnable{ - - /** - * Runnable to update a {@link SuggestionListAdapter} - */ - private class SuggestionResultRunnable implements Runnable{ - - private final List suggestions; - - private SuggestionResultRunnable(List suggestions) { - this.suggestions = suggestions; - } - - @Override - public void run() { - adapter.updateAdapter(suggestions); - } - } - - private final int serviceId; - private final String query; - private final Handler h = new Handler(); - private final Activity a; - private final SuggestionListAdapter adapter; - public SuggestionSearchRunnable(int serviceId, String query, - Activity activity, SuggestionListAdapter adapter) { - this.serviceId = serviceId; - this.query = query; - this.a = activity; - this.adapter = adapter; - } - - @Override - public void run() { - try { - SuggestionExtractor se = - NewPipe.getService(serviceId).getSuggestionExtractorInstance(); - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(a); - String searchLanguageKey = a.getString(R.string.search_language_key); - String searchLanguage = sp.getString(searchLanguageKey, - a.getString(R.string.default_language_value)); - List suggestions = se.suggestionList(query, searchLanguage); - h.post(new SuggestionResultRunnable(suggestions)); - } catch (ExtractionException e) { - ErrorActivity.reportError(h, a, e, null, a.findViewById(android.R.id.content), - ErrorActivity.ErrorInfo.make(ErrorActivity.SEARCHED, - NewPipe.getNameOfService(serviceId), query, R.string.parsing_error)); - e.printStackTrace(); - } catch (IOException e) { - postNewErrorToast(h, R.string.network_error); - e.printStackTrace(); - } catch (Exception e) { - ErrorActivity.reportError(h, a, e, null, a.findViewById(android.R.id.content), - ErrorActivity.ErrorInfo.make(ErrorActivity.SEARCHED, - NewPipe.getNameOfService(serviceId), query, R.string.general_error)); - } - } - - private void postNewErrorToast(Handler h, final int stringResource) { - h.post(new Runnable() { - @Override - public void run() { - Toast.makeText(a, a.getString(stringResource), - Toast.LENGTH_SHORT).show(); - } - }); - } -} \ No newline at end of file diff --git a/app/src/main/java/org/schabi/newpipe/workers/AbstractWorker.java b/app/src/main/java/org/schabi/newpipe/workers/AbstractWorker.java new file mode 100644 index 000000000..e67d5b119 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/workers/AbstractWorker.java @@ -0,0 +1,118 @@ +package org.schabi.newpipe.workers; + +import android.content.Context; +import android.os.Handler; + +import org.schabi.newpipe.extractor.NewPipe; +import org.schabi.newpipe.extractor.StreamingService; +import org.schabi.newpipe.extractor.stream_info.StreamInfo; + +import java.io.InterruptedIOException; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * Common properties of Workers + * + * @author mauriciocolli + */ +@SuppressWarnings("WeakerAccess") +public abstract class AbstractWorker extends Thread { + + private final AtomicBoolean isRunning = new AtomicBoolean(false); + + private final int serviceId; + private Context context; + private Handler handler; + private StreamingService service; + + public AbstractWorker(Context context, int serviceId) { + this.context = context; + this.serviceId = serviceId; + this.handler = new Handler(context.getMainLooper()); + } + + @Override + public void run() { + try { + isRunning.set(true); + service = NewPipe.getService(serviceId); + doWork(serviceId); + } catch (Exception e) { + // Handle the exception only if thread is not interrupted + e.printStackTrace(); + if (!isInterrupted() && !(e instanceof InterruptedIOException) && !(e.getCause() instanceof InterruptedIOException)) { + handleException(e, serviceId); + } + } finally { + isRunning.set(false); + } + } + + /** + * Here is the place that the heavy work is realized + * + * @param serviceId serviceId that was passed when created this object + * + * @throws Exception these exceptions are handled by the {@link #handleException(Exception, int)} + */ + protected abstract void doWork(int serviceId) throws Exception; + + + /** + * Method that handle the exception thrown by the {@link #doWork(int)}. + * + * @param exception {@link Exception} that was thrown by {@link #doWork(int)} + */ + protected abstract void handleException(Exception exception, int serviceId); + + /** + * Return true if the extraction is not completed yet + * + * @return the value of the AtomicBoolean {@link #isRunning} + */ + public boolean isRunning() { + return isRunning.get(); + } + + /** + * Cancel this ExtractorWorker, calling {@link #onDestroy()} and interrupting this thread. + *

+ * Note: Any I/O that is active in the moment that this method is called will be canceled and a Exception will be thrown, because of the {@link #interrupt()}.
+ * This is useful when you don't want the resulting {@link StreamInfo} anymore, but don't want to waste bandwidth, otherwise it'd run till it receives the StreamInfo. + */ + public void cancel() { + onDestroy(); + this.interrupt(); + } + + /** + * Method that discards everything that doesn't need anymore.
+ * Subclasses can override this method to destroy their garbage. + */ + protected void onDestroy() { + this.isRunning.set(false); + this.context = null; + this.handler = null; + this.service = null; + } + + public Handler getHandler() { + return handler; + } + + public StreamingService getService() { + return service; + } + + public int getServiceId() { + return serviceId; + } + + public String getServiceName() { + return service == null ? "none" : service.getServiceInfo().name; + } + + public Context getContext() { + return context; + } +} diff --git a/app/src/main/java/org/schabi/newpipe/workers/ChannelExtractorWorker.java b/app/src/main/java/org/schabi/newpipe/workers/ChannelExtractorWorker.java index 5275688d4..bd4cf1139 100644 --- a/app/src/main/java/org/schabi/newpipe/workers/ChannelExtractorWorker.java +++ b/app/src/main/java/org/schabi/newpipe/workers/ChannelExtractorWorker.java @@ -31,7 +31,7 @@ public class ChannelExtractorWorker extends ExtractorWorker { * Interface which will be called for result and errors */ public interface OnChannelInfoReceive { - void onReceive(ChannelInfo info); + void onReceive(ChannelInfo info, boolean onlyVideos); void onError(int messageId); /** * Called when an unrecoverable error has occurred. @@ -44,12 +44,15 @@ public class ChannelExtractorWorker extends ExtractorWorker { * @param context context for error reporting purposes * @param serviceId id of the request service * @param channelUrl channelUrl of the service (e.g. https://www.youtube.com/channel/UC_aEa8K-EOJ3D6gOs7HcyNg) + * @param pageNumber which page to extract + * @param onlyVideos flag that will be send by {@link OnChannelInfoReceive#onReceive(ChannelInfo, boolean)} * @param callback listener that will be called-back when events occur (check {@link ChannelExtractorWorker.OnChannelInfoReceive}) */ - public ChannelExtractorWorker(Context context, int serviceId, String channelUrl, int pageNumber, OnChannelInfoReceive callback) { + public ChannelExtractorWorker(Context context, int serviceId, String channelUrl, int pageNumber, boolean onlyVideos, OnChannelInfoReceive callback) { super(context, channelUrl, serviceId); this.pageNumber = pageNumber; this.callback = callback; + this.onlyVideos = onlyVideos; } @Override @@ -71,7 +74,7 @@ public class ChannelExtractorWorker extends ExtractorWorker { public void run() { if (isInterrupted() || callback == null) return; - callback.onReceive(channelInfo); + callback.onReceive(channelInfo, onlyVideos); onDestroy(); } }); @@ -107,13 +110,5 @@ public class ChannelExtractorWorker extends ExtractorWorker { }); } } - - public boolean isOnlyVideos() { - return onlyVideos; - } - - public void setOnlyVideos(boolean onlyVideos) { - this.onlyVideos = onlyVideos; - } } diff --git a/app/src/main/java/org/schabi/newpipe/workers/ExtractorWorker.java b/app/src/main/java/org/schabi/newpipe/workers/ExtractorWorker.java index 442a9d8ab..57872b613 100644 --- a/app/src/main/java/org/schabi/newpipe/workers/ExtractorWorker.java +++ b/app/src/main/java/org/schabi/newpipe/workers/ExtractorWorker.java @@ -2,18 +2,12 @@ package org.schabi.newpipe.workers; import android.app.Activity; import android.content.Context; -import android.os.Handler; import android.util.Log; import android.view.View; -import org.schabi.newpipe.extractor.NewPipe; -import org.schabi.newpipe.extractor.StreamingService; -import org.schabi.newpipe.extractor.stream_info.StreamInfo; import org.schabi.newpipe.report.ErrorActivity; -import java.io.InterruptedIOException; import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; /** * Common properties of ExtractorWorkers @@ -21,38 +15,18 @@ import java.util.concurrent.atomic.AtomicBoolean; * @author mauriciocolli */ @SuppressWarnings("WeakerAccess") -public abstract class ExtractorWorker extends Thread { - - private final AtomicBoolean isRunning = new AtomicBoolean(false); - +public abstract class ExtractorWorker extends AbstractWorker { private final String url; - private final int serviceId; - private Context context; - private Handler handler; - private StreamingService service; public ExtractorWorker(Context context, String url, int serviceId) { - this.context = context; + super(context, serviceId); this.url = url; - this.serviceId = serviceId; - this.handler = new Handler(context.getMainLooper()); if (url.length() >= 40) setName("Thread-" + url.substring(url.length() - 11, url.length())); } @Override - public void run() { - try { - isRunning.set(true); - service = NewPipe.getService(serviceId); - doWork(serviceId, url); - } catch (Exception e) { - // Handle the exception only if thread is not interrupted - if (!isInterrupted() && !(e instanceof InterruptedIOException) && !(e.getCause() instanceof InterruptedIOException)) { - handleException(e, serviceId, url); - } - } finally { - isRunning.set(false); - } + protected void doWork(int serviceId) throws Exception { + doWork(serviceId, url); } /** @@ -65,6 +39,10 @@ public abstract class ExtractorWorker extends Thread { */ protected abstract void doWork(int serviceId, String url) throws Exception; + @Override + protected void handleException(Exception exception, int serviceId) { + handleException(exception, serviceId, url); + } /** * Method that handle the exception thrown by the {@link #doWork(int, String)}. @@ -99,63 +77,12 @@ public abstract class ExtractorWorker extends Thread { } if (getContext() instanceof Activity) { - View rootView = getContext() != null ? ((Activity) getContext()).findViewById(android.R.id.content) : null; + View rootView = getContext() instanceof Activity ? ((Activity) getContext()).findViewById(android.R.id.content) : null; ErrorActivity.reportError(getHandler(), getContext(), errorsList, null, rootView, ErrorActivity.ErrorInfo.make(errorUserAction, getServiceName(), url, 0 /* no message for the user */)); } } - /** - * Return true if the extraction is not completed yet - * - * @return the value of the AtomicBoolean {@link #isRunning} - */ - public boolean isRunning() { - return isRunning.get(); - } - - /** - * Cancel this ExtractorWorker, calling {@link #onDestroy()} and interrupting this thread. - *

- * Note: Any I/O that is active in the moment that this method is called will be canceled and a Exception will be thrown, because of the {@link #interrupt()}.
- * This is useful when you don't want the resulting {@link StreamInfo} anymore, but don't want to waste bandwidth, otherwise it'd run till it receives the StreamInfo. - */ - public void cancel() { - onDestroy(); - this.interrupt(); - } - - /** - * Method that discards everything that doesn't need anymore.
- * Subclasses can override this method to destroy their garbage. - */ - protected void onDestroy() { - this.isRunning.set(false); - this.context = null; - this.handler = null; - this.service = null; - } - - public Handler getHandler() { - return handler; - } - public String getUrl() { return url; } - - public StreamingService getService() { - return service; - } - - public int getServiceId() { - return serviceId; - } - - public String getServiceName() { - return service == null ? "none" : service.getServiceInfo().name; - } - - public Context getContext() { - return context; - } } diff --git a/app/src/main/java/org/schabi/newpipe/workers/SearchWorker.java b/app/src/main/java/org/schabi/newpipe/workers/SearchWorker.java new file mode 100644 index 000000000..7d1e28441 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/workers/SearchWorker.java @@ -0,0 +1,127 @@ +package org.schabi.newpipe.workers; + +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; +import android.support.annotation.NonNull; +import android.view.View; + +import org.schabi.newpipe.R; +import org.schabi.newpipe.extractor.exceptions.ExtractionException; +import org.schabi.newpipe.extractor.exceptions.ReCaptchaException; +import org.schabi.newpipe.extractor.search.SearchEngine; +import org.schabi.newpipe.extractor.search.SearchResult; +import org.schabi.newpipe.report.ErrorActivity; + +import java.io.IOException; +import java.util.EnumSet; + +/** + * Return list of results based on a query + * + * @author mauriciocolli + */ +public class SearchWorker extends AbstractWorker { + + private EnumSet filter; + private String query; + private int page; + private OnSearchResult callback; + + /** + * Interface which will be called for result and errors + */ + public interface OnSearchResult { + void onSearchResult(SearchResult result); + void onNothingFound(String message); + void onSearchError(int messageId); + void onReCaptchaChallenge(); + } + + public SearchWorker(Context context, int serviceId, String query, int page, EnumSet filter, OnSearchResult callback) { + super(context, serviceId); + this.callback = callback; + this.query = query; + this.page = page; + this.filter = filter; + } + + public static SearchWorker startForQuery(Context context, int serviceId, @NonNull String query, int page, EnumSet filter, OnSearchResult callback) { + SearchWorker worker = new SearchWorker(context, serviceId, query, page, filter, callback); + worker.start(); + return worker; + } + + @Override + protected void onDestroy() { + super.onDestroy(); + this.callback = null; + } + + @Override + protected void doWork(int serviceId) throws Exception { + SearchEngine searchEngine = getService().getSearchEngineInstance(); + + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getContext()); + String searchLanguageKey = getContext().getString(R.string.search_language_key); + String searchLanguage = sharedPreferences.getString(searchLanguageKey, getContext().getString(R.string.default_language_value)); + + final SearchResult searchResult = SearchResult.getSearchResult(searchEngine, query, page, searchLanguage, filter); + if (callback != null && searchResult != null && !isInterrupted()) getHandler().post(new Runnable() { + @Override + public void run() { + if (isInterrupted() || callback == null) return; + + callback.onSearchResult(searchResult); + onDestroy(); + } + }); + } + + @Override + protected void handleException(final Exception exception, int serviceId) { + if (callback == null || getHandler() == null || isInterrupted()) return; + + if (exception instanceof ReCaptchaException) { + getHandler().post(new Runnable() { + @Override + public void run() { + callback.onReCaptchaChallenge(); + } + }); + } else if (exception instanceof IOException) { + getHandler().post(new Runnable() { + @Override + public void run() { + callback.onSearchError(R.string.network_error); + } + }); + } else if (exception instanceof SearchEngine.NothingFoundException) { + getHandler().post(new Runnable() { + @Override + public void run() { + callback.onNothingFound(exception.getMessage()); + } + }); + } else if (exception instanceof ExtractionException) { + View rootView = getContext() instanceof Activity ? ((Activity) getContext()).findViewById(android.R.id.content) : null; + ErrorActivity.reportError(getHandler(), getContext(), exception, null, rootView, ErrorActivity.ErrorInfo.make(ErrorActivity.SEARCHED, getServiceName(), query, R.string.parsing_error)); + getHandler().post(new Runnable() { + @Override + public void run() { + callback.onSearchError(R.string.parsing_error); + } + }); + } else { + View rootView = getContext() instanceof Activity ? ((Activity) getContext()).findViewById(android.R.id.content) : null; + ErrorActivity.reportError(getHandler(), getContext(), exception, null, rootView, ErrorActivity.ErrorInfo.make(ErrorActivity.SEARCHED, getServiceName(), query, R.string.general_error)); + getHandler().post(new Runnable() { + @Override + public void run() { + callback.onSearchError(R.string.general_error); + } + }); + } + } +} diff --git a/app/src/main/java/org/schabi/newpipe/workers/SuggestionWorker.java b/app/src/main/java/org/schabi/newpipe/workers/SuggestionWorker.java new file mode 100644 index 000000000..6bad06fce --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/workers/SuggestionWorker.java @@ -0,0 +1,108 @@ +package org.schabi.newpipe.workers; + +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; +import android.support.annotation.NonNull; +import android.view.View; + +import org.schabi.newpipe.R; +import org.schabi.newpipe.extractor.SuggestionExtractor; +import org.schabi.newpipe.extractor.exceptions.ExtractionException; +import org.schabi.newpipe.report.ErrorActivity; + +import java.io.IOException; +import java.util.List; + +/** + * Worker that get suggestions based on the query + * + * @author mauriciocolli + */ +public class SuggestionWorker extends AbstractWorker { + + private String query; + private OnSuggestionResult callback; + + /** + * Interface which will be called for result and errors + */ + public interface OnSuggestionResult { + void onSuggestionResult(@NonNull List suggestions); + void onSuggestionError(int messageId); + } + + public SuggestionWorker(Context context, int serviceId, String query, OnSuggestionResult callback) { + super(context, serviceId); + this.callback = callback; + this.query = query; + } + + public static SuggestionWorker startForQuery(Context context, int serviceId, @NonNull String query, OnSuggestionResult callback) { + SuggestionWorker worker = new SuggestionWorker(context, serviceId, query, callback); + worker.start(); + return worker; + } + + @Override + protected void onDestroy() { + super.onDestroy(); + this.callback = null; + this.query = null; + } + + @Override + protected void doWork(int serviceId) throws Exception { + SuggestionExtractor suggestionExtractor = getService().getSuggestionExtractorInstance(); + + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getContext()); + String searchLanguageKey = getContext().getString(R.string.search_language_key); + String searchLanguage = sharedPreferences.getString(searchLanguageKey, getContext().getString(R.string.default_language_value)); + + final List suggestions = suggestionExtractor.suggestionList(query, searchLanguage); + + if (callback != null && suggestions != null && !isInterrupted()) getHandler().post(new Runnable() { + @Override + public void run() { + if (isInterrupted() || callback == null) return; + + callback.onSuggestionResult(suggestions); + onDestroy(); + } + }); + } + + @Override + protected void handleException(final Exception exception, int serviceId) { + if (callback == null || getHandler() == null || isInterrupted()) return; + + if (exception instanceof ExtractionException) { + View rootView = getContext() instanceof Activity ? ((Activity) getContext()).findViewById(android.R.id.content) : null; + ErrorActivity.reportError(getHandler(), getContext(), exception, null, rootView, ErrorActivity.ErrorInfo.make(ErrorActivity.GET_SUGGESTIONS, getServiceName(), query, R.string.parsing_error)); + getHandler().post(new Runnable() { + @Override + public void run() { + callback.onSuggestionError(R.string.parsing_error); + } + }); + } else if (exception instanceof IOException) { + getHandler().post(new Runnable() { + @Override + public void run() { + callback.onSuggestionError(R.string.network_error); + } + }); + } else { + View rootView = getContext() instanceof Activity ? ((Activity) getContext()).findViewById(android.R.id.content) : null; + ErrorActivity.reportError(getHandler(), getContext(), exception, null, rootView, ErrorActivity.ErrorInfo.make(ErrorActivity.GET_SUGGESTIONS, getServiceName(), query, R.string.general_error)); + getHandler().post(new Runnable() { + @Override + public void run() { + callback.onSuggestionError(R.string.general_error); + } + }); + } + + } +}