Browse Source

Downloading and parsing fixes.

pull/24/head
Apostolos Fanakis 8 years ago
parent
commit
3e8365f441
  1. 1
      app/src/main/AndroidManifest.xml
  2. 4
      app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java
  3. 55
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java
  4. 36
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java
  5. 115
      app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java
  6. 82
      app/src/main/java/gr/thmmy/mthmmy/utils/FileManager/ThmmyFile.java

1
app/src/main/AndroidManifest.xml

@ -6,7 +6,6 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<application <application
android:name=".base.BaseApplication" android:name=".base.BaseApplication"

4
app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java

@ -280,7 +280,9 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo
} else { } else {
pUrl = subBoardCol.select("a").first().attr("href"); pUrl = subBoardCol.select("a").first().attr("href");
pTitle = subBoardCol.select("a").first().text(); pTitle = subBoardCol.select("a").first().text();
pMods = subBoardCol.select("div.smalltext").first().text(); if (subBoardCol.select("div.smalltext").first() != null) {
pMods = subBoardCol.select("div.smalltext").first().text();
}
} }
} }
parsedSubBoards.add(new Board(pUrl, pTitle, pMods, pStats, pLastPost, pLastPostUrl)); parsedSubBoards.add(new Board(pUrl, pTitle, pMods, pStats, pLastPost, pLastPostUrl));

55
app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java

@ -1,11 +1,15 @@
package gr.thmmy.mthmmy.activities.topic; package gr.thmmy.mthmmy.activities.topic;
import android.Manifest;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.design.widget.FloatingActionButton; import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearLayoutManager;
@ -58,6 +62,8 @@ public class TopicActivity extends BaseActivity {
* The key to use when putting topic's title String to {@link TopicActivity}'s Bundle. * The key to use when putting topic's title String to {@link TopicActivity}'s Bundle.
*/ */
public static final String BUNDLE_TOPIC_TITLE = "TOPIC_TITLE"; public static final String BUNDLE_TOPIC_TITLE = "TOPIC_TITLE";
private static final int PERMISSIONS_REQUEST_CODE = 69;
static boolean readWriteAccepted;
private static TopicTask topicTask; private static TopicTask topicTask;
//About posts //About posts
private TopicAdapter topicAdapter; private TopicAdapter topicAdapter;
@ -99,6 +105,7 @@ public class TopicActivity extends BaseActivity {
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_topic); setContentView(R.layout.activity_topic);
requestPerms();
Bundle extras = getIntent().getExtras(); Bundle extras = getIntent().getExtras();
topicTitle = extras.getString(BUNDLE_TOPIC_TITLE); topicTitle = extras.getString(BUNDLE_TOPIC_TITLE);
@ -176,11 +183,7 @@ public class TopicActivity extends BaseActivity {
initDecrementButton(previousPage, SMALL_STEP); initDecrementButton(previousPage, SMALL_STEP);
initIncrementButton(nextPage, SMALL_STEP); initIncrementButton(nextPage, SMALL_STEP);
initIncrementButton(lastPage, LARGE_STEP); initIncrementButton(lastPage, LARGE_STEP);
paginationEnabled(false);
firstPage.setEnabled(false);
previousPage.setEnabled(false);
nextPage.setEnabled(false);
lastPage.setEnabled(false);
//Gets posts //Gets posts
topicTask = new TopicTask(); topicTask = new TopicTask();
@ -210,7 +213,36 @@ public class TopicActivity extends BaseActivity {
topicTask.cancel(true); topicTask.cancel(true);
} }
//--------------------------------------BOTTOM NAV BAR METHODS-------------------------------------- @Override
public void onRequestPermissionsResult(int permsRequestCode, @NonNull String[] permissions
, @NonNull int[] grantResults) {
switch (permsRequestCode) {
case PERMISSIONS_REQUEST_CODE:
readWriteAccepted = grantResults[0] == PackageManager.PERMISSION_GRANTED;
break;
}
}
private void requestPerms() { //Runtime permissions for devices with API >= 23
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) {
String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE};
checkSelfPermission(PERMISSIONS_STORAGE[0]);
checkSelfPermission(PERMISSIONS_STORAGE[1]);
requestPermissions(PERMISSIONS_STORAGE, PERMISSIONS_REQUEST_CODE);
} else readWriteAccepted = true;
}
//--------------------------------------BOTTOM NAV BAR METHODS----------------------------------
private void paginationEnabled(boolean enabled) {
firstPage.setEnabled(enabled);
previousPage.setEnabled(enabled);
nextPage.setEnabled(enabled);
lastPage.setEnabled(enabled);
}
private void initIncrementButton(ImageButton increment, final int step) { private void initIncrementButton(ImageButton increment, final int step) {
// Increment once for a click // Increment once for a click
increment.setOnClickListener(new View.OnClickListener() { increment.setOnClickListener(new View.OnClickListener() {
@ -335,7 +367,7 @@ public class TopicActivity extends BaseActivity {
protected void onPreExecute() { protected void onPreExecute() {
progressBar.setVisibility(ProgressBar.VISIBLE); progressBar.setVisibility(ProgressBar.VISIBLE);
paginationEnable(false); paginationEnabled(false);
if (replyFAB.getVisibility() != View.GONE) replyFAB.setEnabled(false); if (replyFAB.getVisibility() != View.GONE) replyFAB.setEnabled(false);
} }
@ -403,7 +435,7 @@ public class TopicActivity extends BaseActivity {
pageIndicator.setText(String.valueOf(thisPage) + "/" + String.valueOf(numberOfPages)); pageIndicator.setText(String.valueOf(thisPage) + "/" + String.valueOf(numberOfPages));
pageRequestValue = thisPage; pageRequestValue = thisPage;
paginationEnable(true); paginationEnabled(true);
if (topicTitle == null || Objects.equals(topicTitle, "")) if (topicTitle == null || Objects.equals(topicTitle, ""))
toolbar.setTitle(parsedTitle); toolbar.setTitle(parsedTitle);
@ -488,11 +520,4 @@ public class TopicActivity extends BaseActivity {
} }
} }
} }
private void paginationEnable(boolean enabled) {
firstPage.setEnabled(enabled);
previousPage.setEnabled(enabled);
nextPage.setEnabled(enabled);
lastPage.setEnabled(enabled);
}
} }

36
app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java

@ -10,7 +10,6 @@ import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.PowerManager;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.v4.content.res.ResourcesCompat; import android.support.v4.content.res.ResourcesCompat;
import android.support.v7.widget.CardView; import android.support.v7.widget.CardView;
@ -93,7 +92,7 @@ class TopicAdapter extends RecyclerView.Adapter<TopicAdapter.MyViewHolder> {
* Index of state indicator in the boolean array. If true quote button for this post is checked. * Index of state indicator in the boolean array. If true quote button for this post is checked.
*/ */
private static final int isQuoteButtonChecked = 2; private static final int isQuoteButtonChecked = 2;
private final MaterialProgressBar progressBar; //private final MaterialProgressBar progressBar;
private DownloadTask downloadTask; private DownloadTask downloadTask;
private TopicActivity.TopicTask topicTask; private TopicActivity.TopicTask topicTask;
@ -167,7 +166,7 @@ class TopicAdapter extends RecyclerView.Adapter<TopicAdapter.MyViewHolder> {
//Initializes properties, array's values will be false by default //Initializes properties, array's values will be false by default
viewProperties.add(new boolean[3]); viewProperties.add(new boolean[3]);
} }
this.progressBar = progressBar; //this.progressBar = progressBar;
downloadTask = new DownloadTask(); downloadTask = new DownloadTask();
this.topicTask = topicTask; this.topicTask = topicTask;
} }
@ -244,8 +243,12 @@ class TopicAdapter extends RecyclerView.Adapter<TopicAdapter.MyViewHolder> {
attached.setOnClickListener(new View.OnClickListener() { attached.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
downloadTask = new DownloadTask(); if (TopicActivity.readWriteAccepted) {
downloadTask.execute(attachedFile); downloadTask = new DownloadTask();
downloadTask.execute(attachedFile);
} else
Toast.makeText(context, "Persmissions missing!", Toast.LENGTH_SHORT)
.show();
} }
}); });
@ -616,17 +619,11 @@ class TopicAdapter extends RecyclerView.Adapter<TopicAdapter.MyViewHolder> {
* Debug Tag for logging debug output to LogCat * Debug Tag for logging debug output to LogCat
*/ */
private static final String TAG = "DownloadTask"; //Separate tag for AsyncTask private static final String TAG = "DownloadTask"; //Separate tag for AsyncTask
private PowerManager.WakeLock mWakeLock;
@Override @Override
protected void onPreExecute() { protected void onPreExecute() {
super.onPreExecute(); super.onPreExecute();
//Locks CPU to prevent going off Toast.makeText(context, "Downloading", Toast.LENGTH_SHORT).show();
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
getClass().getName());
mWakeLock.acquire();
progressBar.setVisibility(View.VISIBLE);
} }
@Override @Override
@ -647,7 +644,10 @@ class TopicAdapter extends RecyclerView.Adapter<TopicAdapter.MyViewHolder> {
Report.e(TAG, "Error while trying to download a file", e); Report.e(TAG, "Error while trying to download a file", e);
return e.toString(); return e.toString();
} catch (OutOfMemoryError e) { } catch (OutOfMemoryError e) {
Report.e(TAG, "Error while trying to download a file", e); Report.e(TAG, e.toString(), e);
return e.toString();
} catch (IllegalStateException e) {
Report.e(TAG, e.toString(), e);
return e.toString(); return e.toString();
} }
return null; return null;
@ -655,12 +655,10 @@ class TopicAdapter extends RecyclerView.Adapter<TopicAdapter.MyViewHolder> {
@Override @Override
protected void onPostExecute(String result) { protected void onPostExecute(String result) {
mWakeLock.release(); if (result != null) {
if (result != null) Toast.makeText(context, "Download failed!", Toast.LENGTH_SHORT).show();
Toast.makeText(context, result, Toast.LENGTH_SHORT).show(); Toast.makeText(context, result, Toast.LENGTH_LONG).show();
else }
Toast.makeText(context, "Download complete", Toast.LENGTH_SHORT).show();
progressBar.setVisibility(View.INVISIBLE);
} }
} }
} }

115
app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java

@ -27,11 +27,10 @@ import okhttp3.RequestBody;
import okhttp3.Response; import okhttp3.Response;
/** /**
This class handles all session related operations (e.g. login, logout) * This class handles all session related operations (e.g. login, logout)
and stores data to SharedPreferences (session information and cookies). * and stores data to SharedPreferences (session information and cookies).
*/ */
public class SessionManager public class SessionManager {
{
//Class TAG //Class TAG
private static final String TAG = "SessionManager"; private static final String TAG = "SessionManager";
@ -66,27 +65,25 @@ public class SessionManager
//Constructor //Constructor
public SessionManager(OkHttpClient client, PersistentCookieJar cookieJar, public SessionManager(OkHttpClient client, PersistentCookieJar cookieJar,
SharedPrefsCookiePersistor cookiePersistor, SharedPreferences sharedPrefs) SharedPrefsCookiePersistor cookiePersistor, SharedPreferences sharedPrefs) {
{
this.client = client; this.client = client;
this.cookiePersistor=cookiePersistor; this.cookiePersistor = cookiePersistor;
this.cookieJar = cookieJar; this.cookieJar = cookieJar;
this.sharedPrefs = sharedPrefs; this.sharedPrefs = sharedPrefs;
} }
//------------------------------------AUTH BEGINS---------------------------------------------- //------------------------------------AUTH BEGINS----------------------------------------------
/** /**
* Login function with two options: (username, password) or nothing (using saved cookies). * Login function with two options: (username, password) or nothing (using saved cookies).
* Always call it in a separate thread. * Always call it in a separate thread.
*/ */
public int login(String... strings) public int login(String... strings) {
{
Report.i(TAG, "Logging in..."); Report.i(TAG, "Logging in...");
//Build the login request for each case //Build the login request for each case
Request request; Request request;
if (strings.length == 2) if (strings.length == 2) {
{
clearSessionData(); clearSessionData();
String loginName = strings[0]; String loginName = strings[0];
@ -101,9 +98,7 @@ public class SessionManager
.url(loginUrl) .url(loginUrl)
.post(formBody) .post(formBody)
.build(); .build();
} } else {
else
{
request = new Request.Builder() request = new Request.Builder()
.url(loginUrl) .url(loginUrl)
.build(); .build();
@ -125,20 +120,16 @@ public class SessionManager
sharedPrefs.edit().putBoolean(LOGIN_SCREEN_AS_DEFAULT, false).apply(); sharedPrefs.edit().putBoolean(LOGIN_SCREEN_AS_DEFAULT, false).apply();
sharedPrefs.edit().putString(USERNAME, extractUserName(document)).apply(); sharedPrefs.edit().putString(USERNAME, extractUserName(document)).apply();
String avatar = extractAvatarLink(document); String avatar = extractAvatarLink(document);
if (avatar!=null) if (avatar != null) {
{ sharedPrefs.edit().putBoolean(HAS_AVATAR, true).apply();
sharedPrefs.edit().putBoolean(HAS_AVATAR,true).apply();
sharedPrefs.edit().putString(AVATAR_LINK, extractAvatarLink(document)).apply(); sharedPrefs.edit().putString(AVATAR_LINK, extractAvatarLink(document)).apply();
} } else
else sharedPrefs.edit().putBoolean(HAS_AVATAR, false).apply();
sharedPrefs.edit().putBoolean(HAS_AVATAR,false).apply();
sharedPrefs.edit().putString(LOGOUT_LINK, HttpUrl.parse(logoutButton.attr("href")).toString()).apply(); sharedPrefs.edit().putString(LOGOUT_LINK, HttpUrl.parse(logoutButton.attr("href")).toString()).apply();
return SUCCESS; return SUCCESS;
} } else {
else
{
Report.i(TAG, "Login failed."); Report.i(TAG, "Login failed.");
//Investigate login failure //Investigate login failure
@ -159,41 +150,35 @@ public class SessionManager
return FAILURE; return FAILURE;
} }
//Handle exception //Handle exception
} } catch (InterruptedIOException e) {
catch (InterruptedIOException e){
Report.i(TAG, "Login InterruptedIOException"); //users cancels LoginTask Report.i(TAG, "Login InterruptedIOException"); //users cancels LoginTask
return CANCELLED; return CANCELLED;
} } catch (IOException e) {
catch (IOException e) {
Report.w(TAG, "Login IOException", e); Report.w(TAG, "Login IOException", e);
return CONNECTION_ERROR; return CONNECTION_ERROR;
} } catch (Exception e) {
catch (Exception e) {
Report.w(TAG, "Login Exception (other)", e); Report.w(TAG, "Login Exception (other)", e);
return EXCEPTION; return EXCEPTION;
} }
} }
/** /**
* A function that checks the validity of the current saved session (if it exists). * A function that checks the validity of the current saved session (if it exists).
* If isLoggedIn() is true, it will call login() with cookies. On failure, this can only return * If isLoggedIn() is true, it will call login() with cookies. On failure, this can only return
* the code FAILURE. CANCELLED, CONNECTION_ERROR and EXCEPTION are simply considered a SUCCESS * the code FAILURE. CANCELLED, CONNECTION_ERROR and EXCEPTION are simply considered a SUCCESS
* (e.g. no internet connection), at least until a more thorough handling of different * (e.g. no internet connection), at least until a more thorough handling of different
* exceptions is implemented (if considered mandatory). * exceptions is implemented (if considered mandatory).
* Always call it in a separate thread in a way that won't hinder performance (e.g. after * Always call it in a separate thread in a way that won't hinder performance (e.g. after
* fragments' data are retrieved). * fragments' data are retrieved).
*/ */
public void validateSession() public void validateSession() {
{
Report.i(TAG, "Validating session..."); Report.i(TAG, "Validating session...");
if(isLoggedIn()) if (isLoggedIn()) {
{
int loginResult = login(); int loginResult = login();
if(loginResult != FAILURE) if (loginResult != FAILURE)
return; return;
} } else if (isLoginScreenDefault())
else if(isLoginScreenDefault())
return; return;
sharedPrefs.edit().putBoolean(LOGIN_SCREEN_AS_DEFAULT, true).apply(); sharedPrefs.edit().putBoolean(LOGIN_SCREEN_AS_DEFAULT, true).apply();
@ -201,10 +186,9 @@ public class SessionManager
} }
/** /**
* Call this function when user explicitly chooses to continue as a guest (UI thread). * Call this function when user explicitly chooses to continue as a guest (UI thread).
*/ */
public void guestLogin() public void guestLogin() {
{
Report.i("TAG", "Continuing as a guest, as chosen by the user."); Report.i("TAG", "Continuing as a guest, as chosen by the user.");
clearSessionData(); clearSessionData();
sharedPrefs.edit().putBoolean(LOGIN_SCREEN_AS_DEFAULT, false).apply(); sharedPrefs.edit().putBoolean(LOGIN_SCREEN_AS_DEFAULT, false).apply();
@ -212,14 +196,13 @@ public class SessionManager
/** /**
* Logout function. Always call it in a separate thread. * Logout function. Always call it in a separate thread.
*/ */
public int logout() public int logout() {
{
Report.i(TAG, "Logging out..."); Report.i(TAG, "Logging out...");
Request request = new Request.Builder() Request request = new Request.Builder()
.url(sharedPrefs.getString(LOGOUT_LINK,"LogoutLink")) .url(sharedPrefs.getString(LOGOUT_LINK, "LogoutLink"))
.build(); .build();
try { try {
@ -271,15 +254,18 @@ public class SessionManager
return sharedPrefs.getBoolean(LOGIN_SCREEN_AS_DEFAULT, true); return sharedPrefs.getBoolean(LOGIN_SCREEN_AS_DEFAULT, true);
} }
//TODO FIX METHOD, THIS MIGHT BE A SECURITY FLAW!! SEE ISSUE #2 MERGED WITH #16
public String getCookieHeader() {
return cookiePersistor.loadAll().get(0).toString();
}
//--------------------------------------GETTERS END--------------------------------------------- //--------------------------------------GETTERS END---------------------------------------------
//------------------------------------OTHER FUNCTIONS------------------------------------------- //------------------------------------OTHER FUNCTIONS-------------------------------------------
private void setPersistentCookieSession() private void setPersistentCookieSession() {
{
List<Cookie> cookieList = cookieJar.loadForRequest(indexUrl); List<Cookie> cookieList = cookieJar.loadForRequest(indexUrl);
if (cookieList.size() == 2) if (cookieList.size() == 2) {
{
if ((cookieList.get(0).name().equals("THMMYgrC00ki3")) if ((cookieList.get(0).name().equals("THMMYgrC00ki3"))
&& (cookieList.get(1).name().equals("PHPSESSID"))) { && (cookieList.get(1).name().equals("PHPSESSID"))) {
Cookie.Builder builder = new Cookie.Builder(); Cookie.Builder builder = new Cookie.Builder();
@ -295,18 +281,16 @@ public class SessionManager
} }
} }
private void clearSessionData() private void clearSessionData() {
{
cookieJar.clear(); cookieJar.clear();
sharedPrefs.edit().clear().apply(); //Clear session data sharedPrefs.edit().clear().apply(); //Clear session data
sharedPrefs.edit().putString(USERNAME, guestName).apply(); sharedPrefs.edit().putString(USERNAME, guestName).apply();
sharedPrefs.edit().putBoolean(LOGGED_IN, false).apply(); //User logs out sharedPrefs.edit().putBoolean(LOGGED_IN, false).apply(); //User logs out
Report.i(TAG,"Session data cleared."); Report.i(TAG, "Session data cleared.");
} }
@Nullable @Nullable
private String extractUserName(Document doc) private String extractUserName(Document doc) {
{
if (doc != null) { if (doc != null) {
Elements user = doc.select("div[id=myuser] > h3"); Elements user = doc.select("div[id=myuser] > h3");
@ -319,13 +303,12 @@ public class SessionManager
return matcher.group(1); return matcher.group(1);
} }
} }
Report.w(TAG,"Extracting username failed!"); Report.w(TAG, "Extracting username failed!");
return null; return null;
} }
@Nullable @Nullable
private String extractAvatarLink(Document doc) private String extractAvatarLink(Document doc) {
{
if (doc != null) { if (doc != null) {
Elements avatar = doc.select("#ava img"); Elements avatar = doc.select("#ava img");
@ -333,7 +316,7 @@ public class SessionManager
return avatar.attr("src"); return avatar.attr("src");
} }
} }
Report.w(TAG,"Extracting avatar's link failed!"); Report.w(TAG, "Extracting avatar's link failed!");
return null; return null;
} }
//----------------------------------OTHER FUNCTIONS END----------------------------------------- //----------------------------------OTHER FUNCTIONS END-----------------------------------------

82
app/src/main/java/gr/thmmy/mthmmy/utils/FileManager/ThmmyFile.java

@ -1,10 +1,18 @@
package gr.thmmy.mthmmy.utils.FileManager; package gr.thmmy.mthmmy.utils.FileManager;
import android.app.DownloadManager;
import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.Environment; import android.os.Environment;
import android.os.StatFs; import android.os.StatFs;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.util.Log;
import android.webkit.MimeTypeMap; import android.webkit.MimeTypeMap;
import android.widget.Toast;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
@ -12,6 +20,7 @@ import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.Objects; import java.util.Objects;
import gr.thmmy.mthmmy.base.BaseActivity;
import mthmmy.utils.Report; import mthmmy.utils.Report;
import okhttp3.Request; import okhttp3.Request;
import okhttp3.Response; import okhttp3.Response;
@ -22,6 +31,7 @@ import static gr.thmmy.mthmmy.base.BaseActivity.getClient;
* Used for downloading and storing a file from the forum using {@link okhttp3}. * Used for downloading and storing a file from the forum using {@link okhttp3}.
* <p>Class has one constructor, {@link #ThmmyFile(URL, String, String)}. * <p>Class has one constructor, {@link #ThmmyFile(URL, String, String)}.
*/ */
@SuppressWarnings("unused")
public class ThmmyFile { public class ThmmyFile {
/** /**
* Debug Tag for logging debug output to LogCat * Debug Tag for logging debug output to LogCat
@ -46,8 +56,8 @@ public class ThmmyFile {
} }
/** /**
* This constructor only creates a ThmmyFile object and <b>does not download</b> the file. To download * This constructor only creates a ThmmyFile object and <b>does not download</b> the file. To
* the file use {@link #download(Context)}! * download the file use {@link #download(Context)} after you provide a url!
* *
* @param fileUrl {@link URL} object with file's url * @param fileUrl {@link URL} object with file's url
* @param filename {@link String} with desired file name * @param filename {@link String} with desired file name
@ -115,23 +125,64 @@ public class ThmmyFile {
/** /**
* Used to download the file. If download is successful file's extension and path will be assigned * Used to download the file. If download is successful file's extension and path will be assigned
* to object's fields and can be accessed using getter methods. * to object's fields and can be accessed using getter methods.
* <p>File is stored in sdcard1/Android/data/Downloads/packageName</p>
* *
* @return the {@link File} if successful, null otherwise * @return null if downloaded with the download service, otherwise the {@link File}
* @throws IOException if the request could not be executed due to cancellation, a connectivity * @throws IOException if the request could not be executed due to cancellation, a
* problem or timeout. Because networks can fail during an exchange, it is possible that the * connectivity problem or timeout. Because networks can fail
* remote server accepted the request before the failure. * during an exchange, it is possible that the remote server
* @throws SecurityException if the requested file is not hosted by the forum. * accepted the request before the failure.
* @throws SecurityException if the requested file is not hosted by the forum.
* @throws IllegalStateException if file's url or filename is not yet set
*/ */
@Nullable @Nullable
public File download(Context context) throws IOException, SecurityException, OutOfMemoryError { public File download(Context context) throws IOException, IllegalStateException, OutOfMemoryError {
if (fileUrl == null) { if (fileUrl == null)
return null; throw new IllegalStateException("Internal error!\nNo url was provided.");
} else if (!Objects.equals(fileUrl.getHost(), "www.thmmy.gr"))
if (!Objects.equals(fileUrl.getHost(), "www.thmmy.gr"))
throw new SecurityException("Downloading files from other sources is not supported"); throw new SecurityException("Downloading files from other sources is not supported");
else if (filename == null || Objects.equals(filename, ""))
throw new IllegalStateException("Internal error!\nNo filename was provided.");
try {
downloadWithManager(context, fileUrl);
} catch (IllegalStateException e) {
return downloadWithoutManager(context, fileUrl);
}
return null;
}
private void downloadWithManager(Context context, @NonNull URL pFileUrl) throws IllegalStateException, IOException {
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(pFileUrl.toString()));
request.addRequestHeader("Cookie", BaseActivity.getSessionManager().getCookieHeader());
request.setDescription("mThmmy");
request.setMimeType(MimeTypeMap.getSingleton().getMimeTypeFromExtension(
MimeTypeMap.getFileExtensionFromUrl(filename)));
request.setTitle(filename);
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
try {
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename);
} catch (IllegalStateException e) {
Report.d(TAG, "External directory not available!", e);
Log.d(TAG, "External directory not available!", e);
throw e;
}
Request request = new Request.Builder().url(fileUrl).build(); DownloadManager manager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
manager.enqueue(request);
context.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Download complete", Toast.LENGTH_SHORT).show();
context.unregisterReceiver(this);
}
}, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
}
@Nullable
private File downloadWithoutManager(Context context, @NonNull URL pFileUrl) throws IOException
, SecurityException, OutOfMemoryError {
Request request = new Request.Builder().url(pFileUrl).build();
Response response = getClient().newCall(request).execute(); Response response = getClient().newCall(request).execute();
if (!response.isSuccessful()) { if (!response.isSuccessful()) {
@ -153,7 +204,8 @@ public class ThmmyFile {
} }
@Nullable @Nullable
private File getOutputMediaFile(Context context, String fileName, String fileInfo) throws OutOfMemoryError, IOException { private File getOutputMediaFile(Context context, String fileName, String fileInfo) throws
OutOfMemoryError, IOException {
File mediaStorageDir; File mediaStorageDir;
String extState = Environment.getExternalStorageState(); String extState = Environment.getExternalStorageState();
if (Environment.isExternalStorageRemovable() && if (Environment.isExternalStorageRemovable() &&

Loading…
Cancel
Save