/*
* Copyright (C) Winson Chiu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cw.kop.autobackground.files;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.os.Handler;
import android.support.v4.content.LocalBroadcastManager;
import android.text.TextUtils;
import android.util.Log;
import android.util.Patterns;
import android.widget.Toast;
import com.dropbox.client2.DropboxAPI;
import com.dropbox.client2.DropboxAPI.Entry;
import com.dropbox.client2.android.AndroidAuthSession;
import com.dropbox.client2.exception.DropboxException;
import com.dropbox.client2.session.AppKeyPair;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.api.client.extensions.android.http.AndroidHttp;
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.DriveScopes;
import com.google.api.services.drive.model.ChildReference;
import com.google.api.services.drive.model.FileList;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import cw.kop.autobackground.BuildConfig;
import cw.kop.autobackground.LiveWallpaperService;
import cw.kop.autobackground.R;
import cw.kop.autobackground.settings.ApiKeys;
import cw.kop.autobackground.settings.AppSettings;
import cw.kop.autobackground.sources.SortData;
import cw.kop.autobackground.sources.Source;
/**
* Created by TheKeeperOfPie on 8/6/2014.
*/
public class DownloadThread extends Thread {
public static final String DROPBOX_FILE_PREFIX = "Dropbox File: ";
public static final String GOOGLE_DRIVE_FILE_PREFIX = "Google Drive File: ";
private static final String CHECK_DOWNLOAD = "Check download settings";
private static final String NO_CHOSEN_METHOD = "No download method chosen";
private static final String NO_WIFI = "No WiFi connection";
private static final String NO_MOBILE = "No mobile data connection";
private static final int NOTIFICATION_ID = 1;
private static final String TAG = DownloadThread.class.getCanonicalName();
private final DropboxAPI<AndroidAuthSession> dropboxAPI;
private final List<Source> sources;
private Context appContext;
private Handler handler;
private String imageDetails = "";
private NotificationManager notificationManager = null;
private Notification.Builder notifyProgress;
private int progressMax;
private int totalDownloaded;
private int totalTarget;
private int numTarget;
private HashSet<String> usedLinks;
private HashSet<String> usedDropboxPaths;
private HashSet<String> usedDrivePaths;
private List<File> downloadedFiles;
private boolean isAnyLowResolution;
private boolean isLowResolution;
private boolean isNotEnoughNew;
private boolean isNotAuthenticated;
private volatile boolean interrupted;
private Drive drive;
public DownloadThread(Context context, List<Source> sources) {
appContext = context;
this.sources = sources;
AppKeyPair appKeys = new AppKeyPair(ApiKeys.DROPBOX_KEY, ApiKeys.DROPBOX_SECRET);
AndroidAuthSession session = new AndroidAuthSession(appKeys);
dropboxAPI = new DropboxAPI<>(session);
if (AppSettings.useDropboxAccount() && !TextUtils.isEmpty(AppSettings.getDropboxAccountToken())) {
dropboxAPI.getSession().setOAuth2AccessToken(AppSettings.getDropboxAccountToken());
}
}
@Override
public void run() {
super.run();
handler = new Handler(appContext.getMainLooper());
if (AppSettings.useDownloadNotification()) {
PendingIntent pendingStopIntent = PendingIntent.getBroadcast(appContext,
0,
new Intent(LiveWallpaperService.STOP_DOWNLOAD),
PendingIntent.FLAG_CANCEL_CURRENT);
notificationManager = (NotificationManager) appContext.getSystemService(Context.NOTIFICATION_SERVICE);
notifyProgress = new Notification.Builder(appContext)
.setContentTitle("AutoBackground")
.setContentText("Downloading images...")
.setSmallIcon(R.drawable.ic_photo_white_24dp);
if (Build.VERSION.SDK_INT >= 16) {
notifyProgress.setPriority(Notification.PRIORITY_MIN);
notifyProgress.addAction(R.drawable.ic_cancel_white_24dp,
"Stop Download",
pendingStopIntent);
}
updateNotification(0);
}
if (!AppSettings.useWifi() && !AppSettings.useMobile()) {
imageDetails += CHECK_DOWNLOAD + AppSettings.DATA_SPLITTER + NO_CHOSEN_METHOD + AppSettings.DATA_SPLITTER;
sendToast(NO_CHOSEN_METHOD);
finish();
return;
}
ConnectivityManager connect = (ConnectivityManager) appContext.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo wifi = connect.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
NetworkInfo mobile = connect.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
boolean hasWifi = wifi != null && wifi.isConnected();
boolean hasMobile = mobile != null && mobile.isConnected();
if (((!AppSettings.useWifi() || !hasWifi)) && ((!AppSettings.useMobile() || !hasMobile))) {
if (AppSettings.useWifi()) {
imageDetails += NO_WIFI + AppSettings.DATA_SPLITTER;
sendToast(NO_WIFI);
}
if (AppSettings.useMobile()) {
imageDetails += NO_MOBILE + AppSettings.DATA_SPLITTER;
sendToast(NO_MOBILE);
}
finish();
return;
}
String downloadCacheDir = AppSettings.getDownloadPath();
File cache = new File(downloadCacheDir);
if (!cache.exists() || !cache.isDirectory()) {
cache.mkdirs();
}
List<Source> validSources = new ArrayList<>();
for (Source source : sources) {
if (!source.getType().equals(AppSettings.FOLDER) && source.isUse()) {
validSources.add(source);
progressMax += source.getNum();
}
}
usedLinks = new HashSet<>();
usedDropboxPaths = new HashSet<>();
usedDrivePaths = new HashSet<>();
if (AppSettings.checkDuplicates()) {
Set<String> rawLinks = AppSettings.getUsedLinks();
for (String link : rawLinks) {
int lastIndex = link.lastIndexOf("Time:");
if (lastIndex > 0) {
if (link.startsWith(DROPBOX_FILE_PREFIX)) {
usedDropboxPaths.add(link.substring(DROPBOX_FILE_PREFIX.length(), lastIndex));
}
else if (link.startsWith(GOOGLE_DRIVE_FILE_PREFIX)) {
usedDrivePaths.add(link.substring(GOOGLE_DRIVE_FILE_PREFIX.length(), lastIndex));
}
else {
usedLinks.add(link.substring(0, lastIndex));
}
}
}
}
downloadedFiles = new ArrayList<>();
for (Source source : validSources) {
if (isInterrupted() || interrupted) {
cancel();
return;
}
try {
if (AppSettings.deleteOldImages()) {
FileHandler.deleteBitmaps(source);
}
String title = source.getTitle();
File file = new File(downloadCacheDir + "/" + title + " " + AppSettings.getImagePrefix());
if (!file.exists() || !file.isDirectory()) {
file.mkdirs();
}
String sourceType = source.getType();
switch (sourceType) {
case AppSettings.WEBSITE:
downloadWebsite(source);
break;
case AppSettings.IMGUR_SUBREDDIT:
downloadImgurSubreddit(source);
break;
case AppSettings.IMGUR_ALBUM:
downloadImgurAlbum(source);
break;
case AppSettings.GOOGLE_PLUS_ALBUM:
downloadPicasa(source);
break;
case AppSettings.GOOGLE_DRIVE_ALBUM:
downloadDrive(source);
break;
case AppSettings.TUMBLR_BLOG:
downloadTumblrBlog(source);
break;
case AppSettings.TUMBLR_TAG:
downloadTumblrTag(source);
break;
case AppSettings.REDDIT_SUBREDDIT:
downloadRedditSubreddit(source);
break;
case AppSettings.DROPBOX_FOLDER:
downloadDropbox(source);
}
if (isInterrupted() || interrupted) {
cancel();
return;
}
numTarget = 0;
totalTarget += source.getNum();
updateNotification(totalTarget);
}
catch (IOException | IllegalArgumentException e) {
sendToast("Invalid data: " + source.getData());
Log.i(TAG, "Invalid data");
}
}
finish();
}
@Override
public void interrupt() {
super.interrupt();
interrupted = true;
Log.i(TAG, "DownloadThread interrupted");
}
private Set<String> compileImageLinks(Document doc, String tag, String attr) {
Elements downloadLinks = doc.select(tag);
Set<String> links = new HashSet<>();
for (Element link : downloadLinks) {
String url = link.attr(attr);
if (!url.contains("http")) {
url = "http:" + url;
}
if (link.attr("width") != null && !TextUtils.isEmpty(link.attr("width"))) {
try {
if (Integer.parseInt(link.attr("width")) < AppSettings.getImageWidth() || Integer.parseInt(
link.attr("height")) < AppSettings.getImageHeight()) {
continue;
}
}
catch (NumberFormatException e) {
}
}
if (AppSettings.checkIsImage(url)) {
links.add(url);
}
else if (AppSettings.forceDownload() && url.length() > 5 && (url.endsWith(".com") || url.endsWith(
".org") || url.endsWith(".net"))) {
links.add(url + AppSettings.JPG);
}
}
return links;
}
private void startDownload(List<String> links, List<String> data, Source source) {
String dir = AppSettings.getDownloadPath();
String title = source.getTitle();
int targetNum = source.getNum();
int numDownloaded = 0;
isLowResolution = false;
Set<File> downloadedFiles = new HashSet<>();
for (int count = 0; numDownloaded < targetNum && count < links.size(); count++) {
if (isInterrupted() || interrupted) {
removeExtras(dir, title, targetNum, downloadedFiles);
return;
}
String randLink = links.get(count);
String randData = data.get(count);
boolean newLink = usedLinks.add(randData);
if (newLink) {
Bitmap bitmap = getImage(randLink);
if (bitmap != null && !interrupted) {
long time = System.currentTimeMillis();
File file = new File(dir + "/" + title + " " + AppSettings.getImagePrefix() + "/" + title + " " + AppSettings.getImagePrefix() + " " + time + ".png");
if (AppSettings.useImageHistory()) {
AppSettings.addUsedLink(randData, time);
if (AppSettings.cacheThumbnails()) {
writeToFileWithThumbnail(bitmap,
randData,
dir,
file,
time);
}
else {
writeToFile(bitmap, randData, file);
}
}
else {
writeToFile(bitmap, randData, file);
}
downloadedFiles.add(file);
numDownloaded++;
updateNotification(++numTarget + totalTarget);
}
}
}
removeExtras(dir, title, targetNum, downloadedFiles);
imageDetails += title + ": " + numDownloaded + " / " + targetNum + " images" + AppSettings.DATA_SPLITTER;
if (numDownloaded < targetNum) {
if (isLowResolution) {
isAnyLowResolution = true;
}
else {
isNotEnoughNew = true;
}
}
totalDownloaded += numDownloaded;
}
private void removeExtras(String dir,
String title,
int targetNum,
Set<File> downloadedFiles) {
File mainDir = new File(dir + "/" + title + " " + AppSettings.getImagePrefix());
FilenameFilter filenameFilter = FileHandler.getImageFileNameFilter();
File[] fileArray = mainDir.listFiles(filenameFilter);
fileArray = fileArray == null ? new File[0] : fileArray;
List<File> files = new ArrayList<>(Arrays.asList(fileArray));
files.removeAll(downloadedFiles);
if (!AppSettings.keepImages()) {
int extra = fileArray.length - targetNum;
while (extra > 0 && files.size() > 0) {
File file = files.get(0);
AppSettings.clearUrl(file.getName());
file.delete();
files.remove(file);
extra--;
}
}
}
private void downloadWebsite(Source source) throws IOException {
if (isInterrupted() || interrupted) {
return;
}
Set<String> imageLinks = new HashSet<>();
List<String> imageList = new ArrayList<>();
Document linkDoc = Jsoup.connect(source.getData()).get();
imageLinks.addAll(compileImageLinks(linkDoc, "a", "href"));
imageLinks.addAll(compileImageLinks(linkDoc, "img", "href"));
imageLinks.addAll(compileImageLinks(linkDoc, "img", "src"));
imageList.addAll(imageLinks);
Log.i(TAG, "imageLinks: " + imageList.toString());
startDownload(imageList, imageList, source);
}
private void downloadImgurSubreddit(Source source) {
if (isInterrupted() || interrupted) {
return;
}
String apiUrl = "https://api.imgur.com/3/gallery/r/" + source.getData();
if (!TextUtils.isEmpty(source.getSort())) {
apiUrl += "/" + AppSettings.getSourceSortParameter(source).getData();
}
Log.i(TAG, "apiUrl: " + apiUrl);
try {
HttpGet httpGet = new HttpGet(apiUrl);
httpGet.setHeader("Authorization", "Client-ID " + ApiKeys.IMGUR_CLIENT_ID);
httpGet.setHeader("Content-Type", "application/json");
String response = getResponse(httpGet);
if (response == null) {
return;
}
JSONObject jsonObject = new JSONObject(response);
JSONArray jArray = jsonObject.getJSONArray("data");
List<String> imageList = new ArrayList<>();
List<String> imagePages = new ArrayList<>();
for (int i = 0; i < jArray.length(); i++) {
JSONObject imageObject = jArray.getJSONObject(i);
imageList.add(imageObject.getString("link"));
String subredditPage = imageObject.getString("reddit_comments");
if (subredditPage != null && !TextUtils.isEmpty(subredditPage)) {
imagePages.add("http://reddit.com" + subredditPage);
}
else {
imagePages.add(imageObject.getString("link"));
}
}
Log.i(TAG, "imageList size: " + imageList.size());
startDownload(imageList, imagePages, source);
}
catch (JSONException e) {
e.printStackTrace();
Log.i(TAG, "JSON parse error");
}
}
private void downloadImgurAlbum(Source source) {
if (isInterrupted() || interrupted) {
return;
}
String albumId = source.getData();
if (albumId.contains("/")) {
albumId = albumId.substring(0, albumId.indexOf("/"));
}
String apiUrl = "https://api.imgur.com/3/album/" + albumId + "/images";
Log.i(TAG, "apiUrl: " + apiUrl);
try {
HttpGet httpGet = new HttpGet(apiUrl);
httpGet.setHeader("Authorization", "Client-ID " + ApiKeys.IMGUR_CLIENT_ID);
httpGet.setHeader("Content-Type", "application/json");
String response = getResponse(httpGet);
if (response == null) {
return;
}
JSONObject jsonObject = new JSONObject(response);
JSONArray jArray = jsonObject.getJSONArray("data");
List<String> imageList = new ArrayList<>();
for (int i = 0; i < jArray.length(); i++) {
JSONObject imageObject = jArray.getJSONObject(i);
imageList.add(imageObject.getString("link"));
}
Log.i(TAG, "imageList size: " + imageList.size());
startDownload(imageList, imageList, source);
}
catch (JSONException e) {
e.printStackTrace();
Log.i(TAG, "JSON parse error");
}
}
private void downloadPicasa(Source source) {
if (isInterrupted() || interrupted) {
return;
}
String data = source.getData();
if (data.contains("user/")) {
data = data.substring(data.indexOf("user/"));
}
else {
return;
}
HttpGet httpGet = new HttpGet("https://picasaweb.google.com/data/feed/api/" + data + "?imgmax=d");
httpGet.setHeader("Authorization", "OAuth " + AppSettings.getGoogleAccountToken());
httpGet.setHeader("X-GData-Client", ApiKeys.PICASA_CLIENT_ID);
httpGet.setHeader("GData-Version", "2");
String response = getResponse(httpGet);
if (response == null) {
return;
}
Document linkDoc = Jsoup.parse(response);
List<String> imageList = new ArrayList<>();
for (Element link : linkDoc.select("media|group")) {
imageList.add(link.select("media|content").attr("url"));
}
startDownload(imageList, imageList, source);
}
private void downloadDrive(Source source) {
String dir = AppSettings.getDownloadPath();
String title = source.getTitle();
int targetNum = source.getNum();
int numDownloaded = 0;
if (drive == null) {
GoogleAccountCredential driveCredential = GoogleAccountCredential.usingOAuth2(
appContext,
Collections.singleton(DriveScopes.DRIVE));
if (TextUtils.isEmpty(AppSettings.getDriveAccountName())) {
isNotAuthenticated = true;
imageDetails += title + ": " + numDownloaded + " / " + targetNum + " images" + AppSettings.DATA_SPLITTER;
return;
}
else {
driveCredential.setSelectedAccountName(AppSettings.getDriveAccountName());
}
drive = new Drive.Builder(
AndroidHttp.newCompatibleTransport(), GsonFactory.getDefaultInstance(),
driveCredential)
.setApplicationName(appContext.getResources()
.getString(R.string.app_name) + "/" + BuildConfig.VERSION_NAME)
.build();
}
try {
Drive.Files.List request = drive.files().list();
final FileList files = request.setQ(
"'" + source.getData() + "' in parents and trashed=false").execute();
final List<com.google.api.services.drive.model.File> fileList = files.getItems();
List<com.google.api.services.drive.model.File> imageFiles = new ArrayList<>();
List<String> imageData = new ArrayList<>();
for (com.google.api.services.drive.model.File file : fileList) {
// Move mimeType to a static variable
if (!file.getMimeType().equals("application/vnd.google-apps.folder") && !usedDrivePaths.contains(file.getId()) && file.getImageMediaMetadata() != null) {
imageFiles.add(file);
imageData.add(GOOGLE_DRIVE_FILE_PREFIX + file.getId());
}
}
isLowResolution = false;
Set<File> downloadedFiles = new HashSet<>();
for (int count = 0; numDownloaded < targetNum && count < imageFiles.size(); count++) {
if (isInterrupted() || interrupted) {
removeExtras(dir, title, targetNum, downloadedFiles);
break;
}
com.google.api.services.drive.model.File imageFile = imageFiles.get(count);
String randData = imageData.get(count);
boolean newLink = usedLinks.add(randData);
if (newLink) {
Bitmap bitmap = null;
FlushedInputStream flushed = null;
try {
int minWidth = AppSettings.getImageWidth();
int minHeight = AppSettings.getImageHeight();
flushed = new FlushedInputStream(drive.files().get(imageFile.getId()).executeMediaAsInputStream());
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
options.inPreferQualityOverSpeed = true;
options.inDither = true;
BitmapFactory.decodeStream(flushed, null, options);
flushed.close();
int bitWidth = options.outWidth;
int bitHeight = options.outHeight;
options.inJustDecodeBounds = false;
Log.i(TAG, "bitWidth: " + bitWidth + " bitHeight: " + bitHeight);
if (bitWidth + 1 < minWidth || bitHeight + 1 < minHeight) {
isLowResolution = true;
bitmap = null;
}
else {
int sampleSize = 1;
if (!AppSettings.useFullResolution()) {
if (bitHeight > minHeight || bitWidth > minWidth) {
final int halfHeight = bitHeight / 2;
final int halfWidth = bitWidth / 2;
while ((halfHeight / sampleSize) > minHeight && (halfWidth / sampleSize) > minWidth) {
sampleSize *= 2;
}
}
}
options.inSampleSize = sampleSize;
imageFile.setMimeType("image/png");
drive.files()
.patch(imageFile.getId(), imageFile)
.execute();
flushed = new FlushedInputStream(drive.files()
.get(imageFile.getId())
.executeMediaAsInputStream());
int len;
int size = 1024;
byte[] buffer;
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
buffer = new byte[size];
while ((len = flushed.read(buffer, 0, size)) != -1) {
outputStream.write(buffer, 0, len);
}
byte[] bytes = outputStream.toByteArray();
bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
}
}
catch (java.io.InterruptedIOException e) {
DownloadThread.this.interrupt();
Log.i(TAG, "Interrupted");
}
catch (Throwable e) {
if (isInterrupted()) {
DownloadThread.this.interrupt();
}
e.printStackTrace();
}
finally {
if (flushed != null) {
flushed.close();
}
}
if (bitmap != null && !interrupted) {
long time = System.currentTimeMillis();
File file = new File(dir + "/" + title + " " + AppSettings.getImagePrefix() + "/" + title + " " + AppSettings.getImagePrefix() + " " + time + ".png");
if (AppSettings.useImageHistory()) {
AppSettings.addUsedLink(randData, time);
if (AppSettings.cacheThumbnails()) {
writeToFileWithThumbnail(bitmap,
randData,
dir,
file,
time);
}
else {
writeToFile(bitmap, randData, file);
}
}
else {
writeToFile(bitmap, randData, file);
}
downloadedFiles.add(file);
numDownloaded++;
updateNotification(++numTarget + totalTarget);
}
}
}
removeExtras(dir, title, targetNum, downloadedFiles);
imageDetails += title + ": " + numDownloaded + " / " + targetNum + " images" + AppSettings.DATA_SPLITTER;
if (numDownloaded < targetNum) {
if (isLowResolution) {
isAnyLowResolution = true;
}
else {
isNotEnoughNew = true;
}
}
totalDownloaded += numDownloaded;
}
catch (IllegalArgumentException | IOException e) {
e.printStackTrace();
}
}
private void downloadTumblrBlog(Source source) {
if (isInterrupted() || interrupted) {
return;
}
try {
HttpGet httpGet = new HttpGet("http://api.tumblr.com/v2/blog/" + source.getData() + ".tumblr.com/posts/photo?api_key=" + ApiKeys.TUMBLR_CLIENT_ID);
String response = getResponse(httpGet);
if (response == null) {
return;
}
JSONObject jsonObject = new JSONObject(response);
JSONArray jArray = jsonObject.getJSONObject("response").getJSONArray("posts");
List<String> imageList = new ArrayList<>();
List<String> imagePages = new ArrayList<>();
for (int i = 0; i < jArray.length(); i++) {
JSONObject postObject = jArray.getJSONObject(i);
String postUrl = postObject.getString("post_url");
JSONArray imageArray = postObject.getJSONArray("photos");
for (int imageIndex = 0; imageIndex < imageArray.length(); imageIndex++) {
imageList.add(imageArray.getJSONObject(imageIndex).getJSONObject("original_size").getString(
"url"));
imagePages.add(postUrl);
}
}
Log.i(TAG, "imageList size: " + imageList.size());
startDownload(imageList, imagePages, source);
}
catch (JSONException e) {
e.printStackTrace();
}
}
private void downloadTumblrTag(Source source) {
try {
HttpGet httpGet = new HttpGet("http://api.tumblr.com/v2/tagged?tag=" + source.getData() + "&api_key=" + ApiKeys.TUMBLR_CLIENT_ID);
String response = getResponse(httpGet);
if (response == null) {
return;
}
JSONObject jsonObject = new JSONObject(response);
JSONArray jArray = jsonObject.getJSONArray("response");
List<String> imageList = new ArrayList<>();
List<String> imagePages = new ArrayList<>();
for (int i = 0; i < jArray.length(); i++) {
try {
JSONObject postObject = jArray.getJSONObject(i);
String postUrl = postObject.getString("post_url");
JSONArray imageArray = postObject.getJSONArray("photos");
for (int imageIndex = 0; imageIndex < imageArray.length(); imageIndex++) {
imageList.add(imageArray.getJSONObject(imageIndex).getJSONObject(
"original_size").getString("url"));
imagePages.add(postUrl);
}
}
catch (JSONException e) {
}
}
Log.i(TAG, "imageList size: " + imageList.size());
startDownload(imageList, imagePages, source);
}
catch (JSONException e) {
e.printStackTrace();
}
}
private void downloadRedditSubreddit(Source source) {
if (isInterrupted() || interrupted) {
return;
}
String apiUrl = "https://reddit.com/r/" + source.getData();
SortData sortData = AppSettings.getSourceSortParameter(source);
if (!TextUtils.isEmpty(source.getSort()) && sortData != null) {
apiUrl += "/" + sortData.getData();
}
apiUrl +=".json?limit=100";
if (!TextUtils.isEmpty(source.getSort()) && sortData != null) {
apiUrl += "&t=" + sortData.getQuery();
}
Log.i(TAG, "apiUrl: " + apiUrl);
try {
HttpGet httpGet = new HttpGet(apiUrl);
httpGet.setHeader("User-Agent",
"AutoBackground/" + BuildConfig.VERSION_NAME + " by TheKeeperOfPie");
String response = getResponse(httpGet);
if (response == null) {
return;
}
JSONObject jsonObject = new JSONObject(response);
Log.i(TAG, "Reddit return JSON: " + jsonObject.toString());
JSONArray jArray = jsonObject.getJSONObject("data").getJSONArray("children");
List<String> imageList = new ArrayList<>();
List<String> imagePages = new ArrayList<>();
for (int i = 0; i < jArray.length(); i++) {
JSONObject linkObject = jArray.getJSONObject(i).getJSONObject("data");
if (i == 0) {
Log.i(TAG, "First object: " + linkObject.toString());
}
String url = linkObject.getString("url");
if (url.contains("imgur") && !AppSettings.checkIsImage(url)) {
url += ".jpg";
}
imageList.add(url);
imagePages.add("https://reddit.com" + linkObject.getString("permalink"));
}
Log.i(TAG, "imageList size: " + imageList.size());
Log.i(TAG, "imageList " + imageList.toString());
Log.i(TAG, "imagePages " + imagePages.toString());
startDownload(imageList, imagePages, source);
}
catch (JSONException e) {
e.printStackTrace();
Log.i(TAG, "JSON parse error");
}
}
private void downloadDropbox(Source source) {
try {
List<Entry> entries = dropboxAPI.metadata(source.getData(), 0, null, true, null).contents;
List<String> imageLinks = new ArrayList<>();
List<String> imageData = new ArrayList<>();
for (Entry entry : entries) {
if (!entry.isDir &&
!usedDropboxPaths.contains(entry.path) &&
(AppSettings.checkIsImage(entry.path))) {
imageLinks.add(dropboxAPI.media(entry.path, true).url);
imageData.add(DROPBOX_FILE_PREFIX + entry.path);
}
}
startDownload(imageLinks, imageData, source);
}
catch (DropboxException e) {
e.printStackTrace();
}
}
private String getResponse(HttpGet httpGet) {
DefaultHttpClient httpClient = new DefaultHttpClient();
InputStream inputStream = null;
BufferedReader reader = null;
String result = null;
try {
HttpResponse response = httpClient.execute(httpGet);
HttpEntity entity = response.getEntity();
inputStream = entity.getContent();
reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"), 8);
StringBuilder stringBuilder = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
stringBuilder.append(line).append("\n");
}
result = stringBuilder.toString();
}
catch (IOException e) {
return null;
}
finally {
try {
if (inputStream != null) {
inputStream.close();
}
if (reader != null) {
reader.close();
}
}
catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
private Bitmap getImage(String url) {
if (Patterns.WEB_URL.matcher(url).matches()) {
InputStream input = null;
try {
int minWidth = AppSettings.getImageWidth();
int minHeight = AppSettings.getImageHeight();
URL imageUrl = new URL(url);
HttpURLConnection connection = (HttpURLConnection) imageUrl.openConnection();
connection.connect();
input = connection.getInputStream();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
options.inPreferQualityOverSpeed = true;
options.inDither = true;
BitmapFactory.decodeStream(input, null, options);
input.close();
int bitWidth = options.outWidth;
int bitHeight = options.outHeight;
options.inJustDecodeBounds = false;
Log.i(TAG, "bitWidth: " + bitWidth + " bitHeight: " + bitHeight);
if (bitWidth + 1 < minWidth || bitHeight + 1 < minHeight) {
isLowResolution = true;
return null;
}
int sampleSize = 1;
if (!AppSettings.useFullResolution()) {
if (bitHeight > minHeight || bitWidth > minWidth) {
final int halfHeight = bitHeight / 2;
final int halfWidth = bitWidth / 2;
while ((halfHeight / sampleSize) > minHeight && (halfWidth / sampleSize) > minWidth) {
sampleSize *= 2;
}
}
}
options.inSampleSize = sampleSize;
connection = (HttpURLConnection) imageUrl.openConnection();
connection.setConnectTimeout(5000);
connection.connect();
input = connection.getInputStream();
int len;
int size = 1024;
byte[] buffer;
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
buffer = new byte[size];
while ((len = input.read(buffer, 0, size)) != -1) {
outputStream.write(buffer, 0, len);
}
byte[] bytes = outputStream.toByteArray();
input.close();
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
if (bitmap == null) {
Log.i(TAG, "Null bitmap");
return null;
}
return bitmap;
}
catch (java.io.InterruptedIOException e) {
DownloadThread.this.interrupt();
Log.i(TAG, "Interrupted");
}
catch (Throwable e) {
if (isInterrupted()) {
DownloadThread.this.interrupt();
}
e.printStackTrace();
}
finally {
if (input != null) {
try {
input.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
}
Log.i(TAG, "Possible malformed URL");
return null;
}
private void writeToFile(Bitmap image, String saveData, File file) {
if (file.isFile()) {
file.delete();
}
FileOutputStream out = null;
try {
out = new FileOutputStream(file);
image.compress(Bitmap.CompressFormat.PNG, 90, out);
AppSettings.setUrl(file.getName(), saveData);
Log.i(TAG, file.getName() + " " + saveData);
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
finally {
try {
if (out != null) {
out.close();
}
}
catch (Throwable e) {
e.printStackTrace();
}
}
image.recycle();
image = null;
System.gc();
}
private void writeToFileWithThumbnail(Bitmap image,
String saveData,
String dir,
File file,
long time) {
if (file.isFile()) {
file.delete();
}
FileOutputStream out = null;
FileOutputStream thumbnailOut = null;
try {
int bitWidth = image.getWidth();
int bitHeight = image.getHeight();
float thumbnailSize = (float) AppSettings.getThumbnailSize();
Bitmap thumbnail;
if (thumbnailSize < bitWidth && thumbnailSize < bitHeight) {
Matrix matrix = new Matrix();
if (bitWidth > bitHeight) {
matrix.postScale(thumbnailSize / bitWidth, thumbnailSize / bitWidth);
}
else {
matrix.postScale(thumbnailSize / bitHeight, thumbnailSize / bitHeight);
}
thumbnail = Bitmap.createBitmap(image, 0, 0, bitWidth, bitHeight, matrix, false);
}
else {
thumbnail = image;
}
out = new FileOutputStream(file);
image.compress(Bitmap.CompressFormat.PNG, 90, out);
File thumbnailCache = new File(dir + "/HistoryCache");
if (!thumbnailCache.exists() || (thumbnailCache.exists() && !thumbnailCache.isDirectory())) {
thumbnailCache.mkdirs();
}
File thumbnailFile = new File(thumbnailCache.getAbsolutePath() + "/" + time + ".png");
thumbnailOut = new FileOutputStream(thumbnailFile);
thumbnail.compress(Bitmap.CompressFormat.PNG, 90, thumbnailOut);
Log.i(TAG, "Thumbnail written: " + thumbnailFile.getAbsolutePath());
AppSettings.setUrl(file.getName(), saveData);
Log.i(TAG, file.getName() + " " + saveData);
thumbnail.recycle();
thumbnail = null;
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
finally {
try {
if (out != null) {
out.close();
}
if (thumbnailOut != null) {
thumbnailOut.close();
}
}
catch (IOException e) {
e.printStackTrace();
}
}
image.recycle();
image = null;
System.gc();
}
private void sendToast(final String message) {
if (AppSettings.useToast()) {
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(appContext, message, Toast.LENGTH_SHORT).show();
}
});
}
}
private void updateNotification(int value) {
if (notificationManager != null && notifyProgress != null) {
if (AppSettings.useDownloadNotification()) {
notifyProgress.setProgress(progressMax, value, false);
if (Build.VERSION.SDK_INT >= 16) {
notificationManager.notify(NOTIFICATION_ID, notifyProgress.build());
}
else {
notificationManager.notify(NOTIFICATION_ID, notifyProgress.getNotification());
}
}
else {
notificationManager.cancel(NOTIFICATION_ID);
}
}
}
private void cancel() {
if (notificationManager != null) {
notificationManager.cancel(NOTIFICATION_ID);
}
Intent resetDownloadIntent = new Intent(FileHandler.DOWNLOAD_TERMINATED);
LocalBroadcastManager.getInstance(appContext).sendBroadcast(resetDownloadIntent);
appContext = null;
AppSettings.checkUsedLinksSize();
FileHandler.setIsDownloading(false);
}
private void finish() {
if (AppSettings.useDownloadNotification()) {
Notification.Builder notifyComplete = new Notification.Builder(appContext)
.setContentTitle("Download Completed")
.setContentText("AutoBackground downloaded " + totalDownloaded + " images")
.setSmallIcon(R.drawable.ic_photo_white_24dp);
Notification notification;
if (Build.VERSION.SDK_INT >= 16) {
notifyComplete.setPriority(Notification.PRIORITY_MAX);
Notification.InboxStyle inboxStyle = new Notification.InboxStyle();
inboxStyle.setBigContentTitle("Downloaded Image Details:");
inboxStyle.addLine("Total images enabled: " + FileHandler.getBitmapList().size());
if (isAnyLowResolution) {
inboxStyle.addLine("Not enough suitable resolution images");
}
if (isNotEnoughNew) {
inboxStyle.addLine("Not enough new images");
}
if (isNotAuthenticated) {
inboxStyle.addLine("Account authentication denied");
}
for (String detail : imageDetails.split(AppSettings.DATA_SPLITTER)) {
inboxStyle.addLine(detail);
}
notifyComplete.setStyle(inboxStyle);
notification = notifyComplete.build();
}
else {
notification = notifyComplete.getNotification();
}
notificationManager.cancel(NOTIFICATION_ID);
notificationManager.notify(NOTIFICATION_ID, notification);
}
Intent cycleIntent = new Intent();
cycleIntent.setAction(LiveWallpaperService.CYCLE_IMAGE);
cycleIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
appContext.sendBroadcast(cycleIntent);
Intent resetDownloadIntent = new Intent(FileHandler.DOWNLOAD_TERMINATED);
LocalBroadcastManager.getInstance(appContext).sendBroadcast(resetDownloadIntent);
Intent intent = new Intent();
intent.setAction(LiveWallpaperService.UPDATE_NOTIFICATION);
intent.putExtra("use", AppSettings.useNotification());
appContext.sendBroadcast(intent);
AppSettings.checkUsedLinksSize();
handler.post(new Runnable() {
@Override
public void run() {
appContext = null;
}
});
Log.i(TAG, "Download Finished");
FileHandler.setIsDownloading(false);
}
}