package adonai.diary_browser;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.RingtoneManager;
import android.os.Handler;
import android.os.Handler.Callback;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.support.v4.app.NotificationCompat;
import android.text.Html;
import android.text.Spanned;
import android.text.TextUtils;
import android.util.Pair;
import android.webkit.MimeTypeMap;
import android.webkit.URLUtil;
import com.j256.ormlite.dao.RuntimeExceptionDao;
import com.squareup.okhttp.Response;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Node;
import org.jsoup.nodes.TextNode;
import org.jsoup.select.Elements;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import adonai.diary_browser.database.DbProvider;
import adonai.diary_browser.pages.Comment;
import adonai.diary_browser.pages.CommentsPage;
import adonai.diary_browser.entities.CredentialsItem;
import adonai.diary_browser.pages.DiaryLinkList;
import adonai.diary_browser.pages.DiaryPage;
import adonai.diary_browser.pages.DiaryProfilePage;
import adonai.diary_browser.pages.DiscussionList;
import adonai.diary_browser.pages.DiscPage;
import adonai.diary_browser.pages.ListPage;
import adonai.diary_browser.pages.Post;
import adonai.diary_browser.pages.SearchPage;
import adonai.diary_browser.pages.TagsPage;
import adonai.diary_browser.pages.Umail;
import adonai.diary_browser.pages.UmailListPage;
import adonai.diary_browser.pages.UmailPage;
import adonai.diary_browser.pages.WebPage;
public class NetworkService extends Service implements Callback, OnSharedPreferenceChangeListener {
private static final int NOTIFICATION_ID = 3; // i swear it's random
private static final int NEWS_NOTIFICATION_ID = 4;
public static final String SHARED_PROP_IMAGES_AUTOLOAD = "images.autoload";
public static final String SHARED_PROP_SERVICE_ALWAYS_RUNNING = "service.always.running";
public static final String SHARED_PROP_SERVICE_NOTIFY_UPDATES = "service.notify.updates";
public static final String SHARED_PROP_SERVICE_KEEP_DEVICE_ON = "service.keep.device.on";
public static final String SHARED_PROP_PRELOAD_THEMES = "preload.themes";
public static final String SHARED_PROP_PRELOAD_UMAIL_QUOTING = "preload.umail.quoting";
public static final String SHARED_PROP_USE_TEXT_LINKS = "use.text.links";
public static final String SHARED_PROP_SCREEN_ORIENTATION = "screen.orientation";
public static final String SHARED_PROP_WEBVIEW_FONT_SIZE = "webview.font.size";
public static final String SHARED_PROP_DEFAULT_TAB = "default.list.tab";
public static final String SHARED_PROP_NEW_ON_NOTIFICATION_CLICK = "new.on.notification.click";
// self state
private static NetworkService mInstance = null;
private static boolean mIsStarting = false;
// diary data
public DiaryHttpClient mNetworkClient = new DiaryHttpClient();
private List<DiaryActivity> mListeners = new ArrayList<>(2);
private SharedPreferences mPreferences;
// settings
private boolean mLoadImages;
private boolean mIsStickyService;
private boolean mNotifyOnUpdates;
private boolean mKeepDeviceOn;
boolean mPreloadThemes;
boolean mPreloadUmails;
boolean mUseTextInsteadOfImages;
boolean mOpenNewLinkOnNotificationClick;
int mOrientation;
// service data
private CacheManager mCache = CacheManager.getInstance();
private PowerManager.WakeLock mWakeLock;
private Handler mHandler;
private Looper mLooper;
private Bitmap mNotificationIcon;
private NotifyState mCurrentLinkSet = new NotifyState();
/*
К сожалению, НЕТ другой возможности запустить сервис.
Контекст способен к запуску сервиса только если цикл его главного потока выполняется.
Поэтому НЕЛЬЗЯ остановить контекст, создающий сервис и подождать пока он запустится
Из-за этого, в частности, и нужен механизм с HANDLE_APP_START.
*/
public static NetworkService getInstance(Context context) {
if (mInstance == null && !mIsStarting) {
context.startService(new Intent(context, NetworkService.class));
mIsStarting = true;
}
return mInstance;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
mPreferences = getApplicationContext().getSharedPreferences(Utils.mPrefsFile, MODE_PRIVATE);
mPreferences.registerOnSharedPreferenceChangeListener(this);
PowerManager mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "diary.client");
mLoadImages = mPreferences.getBoolean(SHARED_PROP_IMAGES_AUTOLOAD, false);
mIsStickyService = mPreferences.getBoolean(SHARED_PROP_SERVICE_ALWAYS_RUNNING, false);
mNotifyOnUpdates = mPreferences.getBoolean(SHARED_PROP_SERVICE_NOTIFY_UPDATES, false);
mKeepDeviceOn = mPreferences.getBoolean(SHARED_PROP_SERVICE_KEEP_DEVICE_ON, false);
mPreloadThemes = mPreferences.getBoolean(SHARED_PROP_PRELOAD_THEMES, true);
mPreloadUmails = mPreferences.getBoolean(SHARED_PROP_PRELOAD_UMAIL_QUOTING, true);
mUseTextInsteadOfImages = mPreferences.getBoolean(SHARED_PROP_USE_TEXT_LINKS, false);
mOpenNewLinkOnNotificationClick = mPreferences.getBoolean(SHARED_PROP_NEW_ON_NOTIFICATION_CLICK, true);
mOrientation = Integer.parseInt(mPreferences.getString(SHARED_PROP_SCREEN_ORIENTATION, "-1")); // default to UNSPECIFIED
final HandlerThread thr = new HandlerThread("ServiceThread");
thr.start();
mLooper = thr.getLooper();
mHandler = new Handler(mLooper, this);
if (mNotifyOnUpdates)
mHandler.sendMessageDelayed(mHandler.obtainMessage(Utils.HANDLE_SERVICE_UPDATE), 300000);
if (mKeepDeviceOn)
mWakeLock.acquire();
if (mIsStickyService)
startForeground(NOTIFICATION_ID, createNotification(UserData.getInstance().getCurrentDiaryPage()));
Bitmap appIcon = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_inverted);
Resources res = getResources();
int height = (int) res.getDimension(android.R.dimen.notification_large_icon_height);
int width = (int) res.getDimension(android.R.dimen.notification_large_icon_width);
mNotificationIcon = Bitmap.createScaledBitmap(appIcon, width, height, false);
mInstance = this;
mIsStarting = false;
}
@Override
public void onDestroy() {
mInstance = null;
if (mWakeLock.isHeld())
mWakeLock.release();
mLooper.quit();
// убираем значок
stopForeground(true);
// убираем вызовы регистрантам
for (DiaryActivity listener : mListeners) {
listener.mUiHandler.removeCallbacksAndMessages(null);
listener.handleUi(Utils.HANDLE_SERVICE_ERROR, null);
}
super.onDestroy();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return mIsStickyService ? START_STICKY : START_NOT_STICKY;
}
public void handleRequest(int opcode, Object message) {
mHandler.sendMessage(mHandler.obtainMessage(opcode, message));
}
public void addListener(DiaryActivity listener) {
if (!mListeners.contains(listener)) {
mListeners.add(listener);
listener.handleFontChange(mPreferences.getString(SHARED_PROP_WEBVIEW_FONT_SIZE, "12"));
}
}
public void removeListener(DiaryActivity listener) {
mListeners.remove(listener);
}
private void notifyListeners(int opCode, Object body) {
for (DiaryActivity listener : mListeners)
listener.handleUi(opCode, body);
}
private void notifyListeners(int opCode) {
notifyListeners(opCode, null);
}
@SuppressWarnings("unchecked")
@Override
public boolean handleMessage(Message message) {
switch (message.what) {
case Utils.HANDLE_SERVICE_UPDATE: { // уведомления о новых комментариях раз в 5 минут
mHandler.sendMessageDelayed(mHandler.obtainMessage(Utils.HANDLE_SERVICE_UPDATE), 300000); // убедимся, что будем уведомлять и дальше
final String dataPage = mNetworkClient.getPageAsString(UserData.getInstance().getFavoritesUrl()); // подойдет любая ссылка с дневников
if (dataPage == null)
break;
final Document rootNode = Jsoup.parse(dataPage);
UserData.getInstance().updateData(rootNode);
notifyListeners(Utils.HANDLE_UPDATE_HEADERS);
final NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (UserData.getInstance().hasNotifications() && mCurrentLinkSet.shouldNotify(UserData.getInstance())) { // старые данные или нет?
mCurrentLinkSet.lastDiaryLink = UserData.getInstance().getNewDiaryLink(); // устанавливаем линки на новые значения
mCurrentLinkSet.lastDiscussionLink = UserData.getInstance().getNewDiscussLink();
mCurrentLinkSet.lastUmailLink = UserData.getInstance().getNewUmailLink();
NotificationCompat.Builder nBuilder = new NotificationCompat.Builder(this);
nBuilder.setContentTitle(getString(R.string.new_comments));
nBuilder.setContentText(
getString(R.string.my_diary) + ": " + UserData.getInstance().getNewDiaryCommentsNum() + " | " +
getString(R.string.discussions) + ": " + UserData.getInstance().getNewDiscussNum() + " | " +
getString(R.string.umail_activity_title) + ": " + UserData.getInstance().getNewUmailNum());
nBuilder.setSmallIcon(R.drawable.ic_launcher_status_icon);
nBuilder.setLargeIcon(mNotificationIcon);
nBuilder.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION));
nBuilder.setTicker(getString(R.string.new_comments) + ": " +
Integer.toString(UserData.getInstance().getNewDiaryCommentsNum() +
UserData.getInstance().getNewDiscussNum() +
UserData.getInstance().getNewUmailNum()));
nBuilder.setOnlyAlertOnce(true);
nBuilder.setAutoCancel(true);
final Intent intent = new Intent(this, DiaryListActivity.class); // при клике на уведомление открываем приложение
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
String newUrl = UserData.getInstance().getMostRecentNotification();
if(mOpenNewLinkOnNotificationClick && newUrl != null) { // we don't support U-Mails for now
intent.putExtra("url", newUrl);
}
nBuilder.setContentIntent(PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
mNotificationManager.notify(NEWS_NOTIFICATION_ID, nBuilder.build()); // запускаем уведомление
} else if (!UserData.getInstance().hasNotifications()) {
mNotificationManager.cancel(NEWS_NOTIFICATION_ID);
}
break;
}
case Utils.HANDLE_JUST_DO_GET: {
if (mNetworkClient.getPageAsString(message.obj.toString()) != null)
notifyListeners(Utils.HANDLE_JUST_DO_GET);
break;
}
case Utils.HANDLE_QUERY_ONLINE: {
final String dataPage = mNetworkClient.getPageAsString("http://www.diary.ru");
if (dataPage == null) { // no connection
notifyListeners(Utils.HANDLE_CONNECTIVITY_ERROR, R.string.connection_error);
break;
}
HashMap<Integer, Spanned> onlineUsers = new HashMap<>(2);
try {
Document rootNode = Jsoup.parse(dataPage);
UserData.getInstance().updateData(rootNode);
notifyListeners(Utils.HANDLE_UPDATE_HEADERS);
Element content = rootNode.getElementById("container");
Element favoritesOnline = content.select("span.sel:containsOwn(в том числе мои избранные) + div.sp").first();
onlineUsers.put(R.string.favourites_online, Html.fromHtml(favoritesOnline.html().replace("/member/", "http://www.diary.ru/member/")));
Element subscribersOnline = content.select("span.sel:containsOwn(и мои постоянные читатели) + div.sp").first();
onlineUsers.put(R.string.subscribers_online, Html.fromHtml(subscribersOnline.html().replace("/member/", "http://www.diary.ru/member/")));
} catch (Exception ignored) {
}
notifyListeners(Utils.HANDLE_QUERY_ONLINE, onlineUsers);
break;
}
case Utils.HANDLE_DELETE_UMAILS: {
final Integer folderFrom = ((Pair<long[], Integer>) message.obj).second;
final long[] ids = ((Pair<long[], Integer>) message.obj).first;
final List<Pair<String, String>> nameValuePairs = new ArrayList<>();
nameValuePairs.add(Pair.create("act", "umail_move"));
nameValuePairs.add(Pair.create("module", "umail"));
nameValuePairs.add(Pair.create("move_from_folder", folderFrom.toString()));
nameValuePairs.add(Pair.create("move_to_folder", "0"));
nameValuePairs.add(Pair.create("signature", UserData.getInstance().getSignature()));
nameValuePairs.add(Pair.create("delm", "Удалить отмеченные"));
for (long id : ids)
nameValuePairs.add(Pair.create("umail_check[]", Long.toString(id)));
mNetworkClient.postPageToString(nameValuePairs);
notifyListeners(Utils.HANDLE_DELETE_UMAILS);
break;
}
case Utils.HANDLE_AUTHORIZE: {
// вытаскиваем последний сохранённый логин
String requested = mPreferences.getString(Utils.KEY_USERNAME, "");
RuntimeExceptionDao<CredentialsItem, String> credDao = DbProvider.getHelper().getCredentialsDao();
CredentialsItem credentials = credDao.queryForId(requested);
final List<Pair<String, String>> nameValuePairs = new ArrayList<>();
nameValuePairs.add(Pair.create("user_login", credentials.getUsername()));
nameValuePairs.add(Pair.create("user_pass", credentials.getPassword()));
nameValuePairs.add(Pair.create("save", "on"));
String loginScreen = mNetworkClient.postPageToString(Utils.LOGIN_PAGE, nameValuePairs);
if (loginScreen == null) { // no connection
notifyListeners(Utils.HANDLE_CONNECTIVITY_ERROR, R.string.connection_error);
break;
}
if(loginScreen.contains(DiaryHttpClient.CLOUDFLARE_ANCHOR) && !mNetworkClient.hasCookie("cf_clearance")) {
notifyListeners(Utils.HACKING_CLOUDFLARE);
if(mNetworkClient.cloudFlareSolve(loginScreen)) {
loginScreen = mNetworkClient.postPageToString(Utils.LOGIN_PAGE, nameValuePairs);
} else { // couldn't solve
notifyListeners(Utils.HANDLE_CONNECTIVITY_ERROR, R.string.captcha_error);
break;
}
}
if(loginScreen.contains("недоступен")) {
notifyListeners(Utils.HANDLE_CONNECTIVITY_ERROR, R.string.page_incorrect);
break;
}
if(loginScreen.contains("CAPTCHA")) {
notifyListeners(Utils.HANDLE_CONNECTIVITY_ERROR, R.string.captcha_error);
break;
}
if (!mNetworkClient.hasCookie("user_login") || !mNetworkClient.hasCookie("user_pass")) { // not authorized
notifyListeners(Utils.HANDLE_AUTHORIZATION_ERROR);
break;
}
UserData.getInstance().setAuthorized(true);
String mainPage = mNetworkClient.getPageAsString(Utils.MAIN_PAGE);
if(mainPage == null) {
notifyListeners(Utils.HANDLE_CONNECTIVITY_ERROR, R.string.connection_error);
break;
}
UserData.getInstance().updateData(serializeMainPage(mainPage)); // get initial links
notifyListeners(Utils.HANDLE_AUTHORIZE);
break;
}
case Utils.HANDLE_GET_DISCUSSION_LIST_DATA: {
final int pos = (Integer) ((ArrayList<?>) message.obj).get(0);
final DiscPage dList = (DiscPage) ((ArrayList<?>) message.obj).get(1);
final boolean onlyNew = (Boolean) ((ArrayList<?>) message.obj).get(2);
String jsURL = dList.getURL();
if (onlyNew)
jsURL = jsURL + "&new";
final String dataPage = mNetworkClient.getPageAsString(jsURL);
if (dataPage == null) {
notifyListeners(Utils.HANDLE_CONNECTIVITY_ERROR, R.string.connection_error);
break;
}
serializeDiscussions(dataPage, dList.getDiscussions());
notifyListeners(Utils.HANDLE_GET_DISCUSSION_LIST_DATA, pos);
break;
}
case Utils.HANDLE_PICK_URL: {
final String URL = ((Pair<String, Boolean>) message.obj).first;
boolean reload = ((Pair<String, Boolean>) message.obj).second;
checkUrlAndHandle(URL, reload);
break;
}
case Utils.HANDLE_OPEN_FOLDER: {
String url = (String) message.obj;
mNetworkClient.setCurrentUrl(mNetworkClient.resolve(url));
final String uFolder = mNetworkClient.getPageAsString(url);
if (uFolder == null) {
notifyListeners(Utils.HANDLE_CONNECTIVITY_ERROR, R.string.connection_error);
break;
}
serializeUmailListPage(uFolder);
notifyListeners(Utils.HANDLE_OPEN_FOLDER);
break;
}
case Utils.HANDLE_OPEN_MAIL: {
String url = (String) message.obj;
mNetworkClient.setCurrentUrl(mNetworkClient.resolve(url));
final String uMail = mNetworkClient.getPageAsString(url);
if (uMail == null) {
notifyListeners(Utils.HANDLE_CONNECTIVITY_ERROR, R.string.connection_error);
break;
}
serializeUmailPage(uMail);
notifyListeners(Utils.HANDLE_OPEN_MAIL);
break;
}
case Utils.HANDLE_DELETE_POST_DRAFT:
case Utils.HANDLE_DELETE_POST: {
final String id = (String) message.obj;
final List<Pair<String, String>> postParams = new ArrayList<>();
postParams.add(Pair.create("module", "journal"));
postParams.add(Pair.create("act", "del_post_post"));
postParams.add(Pair.create("post_id", id));
postParams.add(Pair.create("yes", "Да"));
if(message.what == Utils.HANDLE_DELETE_POST_DRAFT) { // удаляем черновик
postParams.add(Pair.create("draft", ""));
}
mNetworkClient.postPageToString(postParams);
handleRequest(Utils.HANDLE_PICK_URL, new Pair<>(mNetworkClient.getCurrentUrl(), true));
break;
}
case Utils.HANDLE_REPOST: {
final String URL = (String) message.obj;
final String dataPage = mNetworkClient.getPageAsString(URL);
if (dataPage == null) {
notifyListeners(Utils.HANDLE_CONNECTIVITY_ERROR, R.string.connection_error);
break;
}
try {
final Post sendPost = serializePostEditPage(dataPage);
sendPost.diaryID = UserData.getInstance().getOwnProfileId();
notifyListeners(Utils.HANDLE_REPOST, sendPost);
break;
} catch (NullPointerException ex) {
notifyListeners(Utils.HANDLE_CONNECTIVITY_ERROR, R.string.page_incorrect);
break;
}
}
case Utils.HANDLE_DELETE_COMMENT: {
final String id = (String) message.obj;
mNetworkClient.getPageAsString(((DiaryPage) UserData.getInstance().getCurrentDiaryPage()).getDiaryUrl() + "?delcomment&commentid=" + id + "&js&signature=" + UserData.getInstance().getSignature());
handleRequest(Utils.HANDLE_PICK_URL, new Pair<>(mNetworkClient.getCurrentUrl(), true));
break;
}
case Utils.HANDLE_DELETE_TAG: {
final String referer = (String) message.obj;
final List<Pair<String, String>> nameValuePairs = new ArrayList<>();
nameValuePairs.add(Pair.create("referer", referer));
nameValuePairs.add(Pair.create("signature", UserData.getInstance().getSignature()));
nameValuePairs.add(Pair.create("confirm", "Да"));
mNetworkClient.postPageToString(referer, nameValuePairs);
handleRequest(Utils.HANDLE_PICK_URL, new Pair<>(mNetworkClient.getCurrentUrl(), true));
break;
}
case Utils.HANDLE_EDIT_POST: {
final String url = (String) message.obj;
final String dataPage = mNetworkClient.getPageAsString(url);
if (dataPage == null) {
notifyListeners(Utils.HANDLE_CONNECTIVITY_ERROR, R.string.connection_error);
break;
}
try {
final Post sendPost = serializePostEditPage(dataPage);
sendPost.postID = url.substring(url.lastIndexOf("=") + 1);
sendPost.diaryID = ((DiaryPage) UserData.getInstance().getCurrentDiaryPage()).getDiaryId();
sendPost.postType = url.endsWith("draft") ? "draft" : "";
notifyListeners(Utils.HANDLE_EDIT_POST, sendPost);
break;
} catch (NullPointerException ex) { // cannot serialize
notifyListeners(Utils.HANDLE_CONNECTIVITY_ERROR, R.string.page_incorrect);
break;
}
}
case Utils.HANDLE_PRELOAD_THEMES: {
// handle 'favorite' page case
String currentUrl = ((DiaryPage) UserData.getInstance().getCurrentDiaryPage()).getDiaryUrl();
String diaryUrl = currentUrl.contains("/")
? currentUrl.substring(0, currentUrl.lastIndexOf('/') + 1)
: currentUrl;
final String URL = diaryUrl + "?newpost";
final String dataPage = mNetworkClient.getPageAsString(URL);
if (dataPage == null) {
notifyListeners(Utils.HANDLE_CONNECTIVITY_ERROR, R.string.connection_error);
break;
}
if (dataPage.contains("Нельзя опубликовать свою запись в чужом дневнике")) {
notifyListeners(Utils.HANDLE_CONNECTIVITY_ERROR, R.string.closed_error);
break;
}
final Post sendPost = serializePostEditPage(dataPage);
if (sendPost == null) { // additional check due to nullptrs
notifyListeners(Utils.HANDLE_CONNECTIVITY_ERROR, R.string.connection_error);
break;
}
sendPost.diaryID = ((DiaryPage) UserData.getInstance().getCurrentDiaryPage()).getDiaryId();
notifyListeners(Utils.HANDLE_PRELOAD_THEMES, sendPost);
break;
}
case Utils.HANDLE_PRELOAD_UMAIL: {
final int type = (int) message.obj;
final String umailId = UserData.getInstance().getCurrentUmailPage().getUmailId();
final String url = "http://www.diary.ru/u-mail/read/?" + (type == Utils.UMAIL_REPLY ? "reply" : "forward") + "&u_id=" + umailId;
final String dataPage = mNetworkClient.getPageAsString(url);
if (dataPage == null) {
notifyListeners(Utils.HANDLE_CONNECTIVITY_ERROR, R.string.connection_error);
break;
}
final Umail sendMail = serializeUmailEditPage(dataPage, type);
if (sendMail == null) { // additional check due to nullptrs
notifyListeners(Utils.HANDLE_CONNECTIVITY_ERROR, R.string.connection_error);
break;
}
notifyListeners(Utils.HANDLE_PRELOAD_UMAIL, sendMail);
break;
}
case Utils.HANDLE_EDIT_COMMENT: {
final String URL = (String) message.obj;
final String dataPage = mNetworkClient.getPageAsString(URL);
if (dataPage == null) {
notifyListeners(Utils.HANDLE_CONNECTIVITY_ERROR, R.string.connection_error);
break;
}
try {
Comment sendComment = serializeCommentEditPage(dataPage);
sendComment.commentID = URL.substring(URL.lastIndexOf("=") + 1);
sendComment.postID = ((CommentsPage) UserData.getInstance().getCurrentDiaryPage()).getPostId();
notifyListeners(Utils.HANDLE_EDIT_COMMENT, sendComment);
break;
} catch (NullPointerException ex) { // cannot serialize
notifyListeners(Utils.HANDLE_CONNECTIVITY_ERROR, R.string.page_incorrect);
break;
}
}
case Utils.HANDLE_REQUEST_DIARY: {
String diaryName = (String) message.obj;
final List<Pair<String, String>> nameValuePairs = new ArrayList<>();
nameValuePairs.add(Pair.create("module", "registration"));
nameValuePairs.add(Pair.create("act", "new_journal_post"));
nameValuePairs.add(Pair.create("journal_act", "1"));
nameValuePairs.add(Pair.create("diary_title", diaryName));
nameValuePairs.add(Pair.create("community_title", ""));
nameValuePairs.add(Pair.create("signature", UserData.getInstance().getSignature()));
String response = mNetworkClient.postPageToString(nameValuePairs);
if(response == null) {
notifyListeners(Utils.HANDLE_CONNECTIVITY_ERROR, R.string.connection_error);
break;
}
String mainPage = mNetworkClient.getPageAsString(Utils.MAIN_PAGE);
if(mainPage == null) {
notifyListeners(Utils.HANDLE_CONNECTIVITY_ERROR, R.string.connection_error);
break;
}
UserData.getInstance().updateData(serializeMainPage(mainPage)); // get initial links
notifyListeners(Utils.HANDLE_REQUEST_DIARY, true);
break;
}
default:
return false;
}
return true;
}
/**
* Страничка редактирования поста, напр. http://dron01.diary.ru/?editpost&postid=207138980
* @param dataPage html-контент странички в виде строки
*/
private Post serializePostEditPage(String dataPage) {
notifyListeners(Utils.HANDLE_PROGRESS);
final Element rootNode = Jsoup.parse(dataPage).select("div.section").first(); // выбираем окошко с текстом
final Post result = new Post();
result.title = rootNode.select("input#postTitle.text").val();
result.content = rootNode.select("textarea#message").text();
final Elements communityThemes = rootNode.select("input[id^=favtg]");
for (Element theme : communityThemes)
result.predefinedTags.put(theme.val(), theme.hasAttr("checked"));
result.themes += rootNode.select("input#tags.text").val();
result.mood = rootNode.select("input#atMood.text").val();
result.music = rootNode.select("input#atMusic.text").val();
result.pollTitle = rootNode.select("input#queti.text").val();
if (!result.pollTitle.isEmpty()) // если есть опрос
{
result.pollAnswer1 = rootNode.select("input#answer1i.text.poll_answer").val();
result.pollAnswer2 = rootNode.select("input#answer2i.text.poll_answer").val();
result.pollAnswer3 = rootNode.select("input#answer3i.text.poll_answer").val();
result.pollAnswer4 = rootNode.select("input#answer4i.text.poll_answer").val();
result.pollAnswer5 = rootNode.select("input#answer5i.text.poll_answer").val();
result.pollAnswer6 = rootNode.select("input#answer6i.text.poll_answer").val();
result.pollAnswer7 = rootNode.select("input#answer7i.text.poll_answer").val();
result.pollAnswer8 = rootNode.select("input#answer8i.text.poll_answer").val();
result.pollAnswer9 = rootNode.select("input#answer9i.text.poll_answer").val();
result.pollAnswer10 = rootNode.select("input#answer10i.text.poll_answer").val();
}
result.closeAccessMode = rootNode.select("[id^=closeaccessmode]").select("[checked]").val();
if (!result.closeAccessMode.isEmpty()) {
result.closeText = rootNode.select("textarea#close_text").text();
if (result.closeAccessMode.equals("3"))
result.closeAllowList = rootNode.select("textarea#access_list").text();
if (result.closeAccessMode.equals("2"))
result.closeDenyList = rootNode.select("textarea#access_list").text();
}
result.noComments = rootNode.select("input#nocomm").hasAttr("checked");
return result;
}
/**
* Страничка редактирования U-mail, напр. http://www.diary.ru/u-mail/read/?forward&u_id=320286777
* @param dataPage html-контент странички в виде строки
*/
private Umail serializeUmailEditPage(String dataPage, int type) {
notifyListeners(Utils.HANDLE_PROGRESS);
final Element rootNode = Jsoup.parse(dataPage);
if (rootNode == null)
return null;
final Umail result = new Umail();
result.messageTheme = UserData.getInstance().getCurrentUmailPage().getMessageTheme();
result.reMessage = rootNode.select("textarea#remessage").first().ownText();
if (type == Utils.UMAIL_REPLY) {
result.receiver = UserData.getInstance().getCurrentUmailPage().getSenderName();
}
return result;
}
/**
* Главная страница - http://www.diary.ru
* @param dataPage html-контент странички в виде строки
*/
private Element serializeMainPage(String dataPage) {
Element rootNode = Jsoup.parse(dataPage).select("div#top").first(); // выбираем окошко с текстом
return rootNode;
}
/**
* Страничка редактирования коммента, напр. http://dron01.diary.ru/?editcomment&commentid=698940371
* @param dataPage html-контент странички в виде строки
*/
private Comment serializeCommentEditPage(String dataPage) {
notifyListeners(Utils.HANDLE_PROGRESS);
Element rootNode = Jsoup.parse(dataPage).select("textarea#message").first(); // выбираем окошко с текстом
Comment result = new Comment();
result.content = rootNode.text();
return result;
}
/**
* Страничка списка дневников, напр. http://www.diary.ru/list/?act=show&show=&l=&sort=&ord=&exact_match=&fgroup_id=0
* @param dataPage html-контент странички в виде строки
*/
private void serializeDiaryListPage(String dataPage) {
notifyListeners(Utils.HANDLE_PROGRESS);
Document rootNode = Jsoup.parse(dataPage);
UserData.getInstance().updateData(rootNode);
notifyListeners(Utils.HANDLE_UPDATE_HEADERS);
UserData.getInstance().setCurrentDiaries(new DiaryLinkList<>(mNetworkClient.getCurrentUrl()));
Element table = rootNode.getElementsByAttributeValue("class", "table r").first();
if (table == null) // Нет вообще никаких дневников, заканчиваем
return;
Element pages = rootNode.select("table.pages").first();
if (pages != null)
UserData.getInstance().getCurrentDiaries().setPageLinks(Html.fromHtml(pages.outerHtml()));
Elements rows = table.select("tr:gt(0)");
for (Element row : rows) {
ListPage diary = new ListPage();
Elements columns = row.children();
diary.setTitle(columns.get(1).getElementsMatchingOwnText(".+").first().text());
diary.setPageHint(columns.get(1).getElementsByTag("em").text());
diary.setURL(columns.get(1).children().attr("href"));
diary.setAuthor(columns.get(2).text());
String authorData = columns.get(2).children().attr("href");
//diary.setAuthorURL(authorData);
diary.setAuthorID(authorData.substring(authorData.lastIndexOf("?") + 1));
diary.setLastUpdate(columns.get(5).text());
diary.setLastUpdateUrl(columns.get(5).children().attr("href"));
UserData.getInstance().getCurrentDiaries().add(diary);
}
}
/**
* Страничка какого-либо дневника, напр. http://dron01.diary.ru/
* @param dataPage html-контент странички в виде строки
*/
private void serializeDiaryPage(String dataPage) {
notifyListeners(Utils.HANDLE_PROGRESS);
Document rootNode = Jsoup.parse(dataPage);
UserData.getInstance().updateData(rootNode);
notifyListeners(Utils.HANDLE_UPDATE_HEADERS);
DiaryPage scannedDiary = new DiaryPage(mNetworkClient.getCurrentUrl());
Element diaryTag = rootNode.select("[id=authorName]").first();
if (diaryTag != null) {
String authorProfile = diaryTag.getElementsByTag("a").last().attr("href");
scannedDiary.setDiaryId(authorProfile.substring(authorProfile.lastIndexOf("?") + 1));
scannedDiary.userLinks.put(getString(R.string.author_diary), scannedDiary.getDiaryUrl());
scannedDiary.userLinks.put(getString(R.string.author_profile), authorProfile);
}
// заполняем ссылки (пока что только какие можем обработать)
// TODO: сделать generic-обработчик всех таких ссылок и вынести в новую процедуру (убрать tags)
Elements userLinks = rootNode.select("li#tagslistlink, div#thisCommunityMember li, div#thisCommunity li, div#thisDiaryLinks li");
for (Element link : userLinks)
if (link.id().matches("communityMyPosts|communityFav|communityQuote|authorFav|authorQuot|tagslistlink"))
scannedDiary.userLinks.put(link.child(0).text(), link.child(0).attr("href")); //they all contain <a> tag first
notifyListeners(Utils.HANDLE_PROGRESS_2);
Elements postsArea = rootNode.select("[id~=post\\d+], div.pageBar");
Elements result = postsArea.clone();
Document resultPage = Document.createShell(mNetworkClient.getCurrentUrl());
resultPage.title(rootNode.title());
for (Element to : result) {
resultPage.body().appendChild(to);
}
mutateContent(resultPage);
scannedDiary.setContent(resultPage.html());
scannedDiary.setTitle(resultPage.title());
UserData.getInstance().setCurrentDiaryPage(scannedDiary);
}
/**
* Страничка поиска, напр. http://www.diary.ru/search/?q=nothing
* @param dataPage html-контент странички в виде строки
*/
private void serializeSearchPage(String dataPage) {
notifyListeners(Utils.HANDLE_PROGRESS);
final Document rootNode = Jsoup.parse(dataPage);
UserData.getInstance().updateData(rootNode);
notifyListeners(Utils.HANDLE_UPDATE_HEADERS);
final SearchPage scannedSearch = new SearchPage(mNetworkClient.getCurrentUrl());
notifyListeners(Utils.HANDLE_PROGRESS_2);
final String searchText = rootNode.select("input[name=q]").val();
final Elements postsArea = rootNode.select("[id~=post\\d+], div#pageBar");
if (postsArea.isEmpty()) { // Нет вообще никаких постов, заканчиваем
notifyListeners(Utils.HANDLE_NOTFOUND_ERROR);
return;
}
final Elements result = postsArea.clone();
final Document resultPage = Document.createShell(mNetworkClient.getCurrentUrl());
resultPage.title(rootNode.title());
for (final Element to : result)
resultPage.body().appendChild(to);
mutateContent(resultPage);
scannedSearch.setContent(resultPage.html());
scannedSearch.setTitle(resultPage.title() + searchText);
UserData.getInstance().setCurrentDiaryPage(scannedSearch);
}
/**
* Страничка комментариев к к посту, напр. http://dron01.diary.ru/p207138980.htm
* @param dataPage html-контент странички в виде строки
*/
private void serializeCommentsPage(String dataPage) throws IOException {
notifyListeners(Utils.HANDLE_PROGRESS);
Document rootNode = Jsoup.parse(dataPage);
UserData.getInstance().updateData(rootNode);
notifyListeners(Utils.HANDLE_UPDATE_HEADERS);
CommentsPage scannedPost = new CommentsPage(mNetworkClient.getCurrentUrl());
Element diaryTag = rootNode.select("#authorName").first();
if (diaryTag != null) {
String authorProfile = diaryTag.getElementsByTag("a").last().attr("href");
scannedPost.setDiaryId(authorProfile.substring(authorProfile.lastIndexOf("?") + 1));
scannedPost.userLinks.put(getString(R.string.author_diary), scannedPost.getDiaryUrl());
scannedPost.userLinks.put(getString(R.string.author_profile), authorProfile);
}
Elements userLinks = rootNode.select("div#thisCommunityMember li, div#thisCommunity li, div#thisDiaryLinks li");
for (Element link : userLinks)
if (link.id().equals("communityMyPosts") || link.id().equals("communityFav") || link.id().equals("communityQuote") ||
link.id().equals("authorFav") || link.id().equals("authorQuot"))
scannedPost.userLinks.put(link.text(), link.child(0).attr("href")); //they all contain <a> tag first
notifyListeners(Utils.HANDLE_PROGRESS_2);
Elements effectiveAreas = rootNode.select("[id~=post\\d+], [id~=comment\\d+], div.pageBar");
if (effectiveAreas.isEmpty()) { // Нет вообще никаких постов, заканчиваем
notifyListeners(Utils.HANDLE_NOTFOUND_ERROR);
return;
}
Elements result = effectiveAreas.clone();
Element urlNode = result.first().getElementsByClass("postLinksBackg").first();
if (urlNode != null) {
String postURL = urlNode.getElementsByTag("a").attr("href");
scannedPost.setPostId(postURL.substring(postURL.lastIndexOf('p') + 1, postURL.lastIndexOf('.')));
}
Document resultPage = Document.createShell(mNetworkClient.getCurrentUrl());
resultPage.title(rootNode.title());
for (Element to : result) {
resultPage.body().appendChild(to);
}
mutateContent(resultPage);
scannedPost.setContent(resultPage.html());
scannedPost.setTitle(resultPage.title());
UserData.getInstance().setCurrentDiaryPage(scannedPost);
}
/**
* Страничка профиля, напр. http://www.diary.ru/member/?1594420
* @param dataPage html-контент странички в виде строки
*/
private void serializeProfilePage(String dataPage) {
notifyListeners(Utils.HANDLE_PROGRESS);
Document rootNode = Jsoup.parse(dataPage);
UserData.getInstance().updateData(rootNode);
notifyListeners(Utils.HANDLE_UPDATE_HEADERS);
DiaryProfilePage profilePage = new DiaryProfilePage(mNetworkClient.getCurrentUrl());
Elements effectiveAreas = rootNode.select("div#contant");
Elements result = effectiveAreas.clone();
notifyListeners(Utils.HANDLE_PROGRESS_2);
Document resultPage = Document.createShell(mNetworkClient.getCurrentUrl());
resultPage.title(rootNode.title());
for (Element to : result)
resultPage.body().appendChild(to);
// добавляем Umail к профилям
Element userName = resultPage.select("h2 + p > b").first();
Element contactsLine = resultPage.select("p:containsOwn(Контакты:)").first();
if(userName != null && contactsLine != null) {
try {
String usernameEncoded = URLEncoder.encode(userName.text(), "windows-1251");
String umailLink = "/u-mail/?new&username=" + usernameEncoded;
contactsLine.append(String.format("<a href='%s'>U-Mail</a>", umailLink));
} catch (UnsupportedEncodingException e) {
// never happens
}
}
mutateContent(resultPage);
profilePage.setContent(resultPage.html());
profilePage.setTitle(resultPage.title());
UserData.getInstance().setCurrentDiaryPage(profilePage);
}
/**
* Страничка тэгов дневника, напр. http://dron01.diary.ru/?tags
* @param dataPage html-контент странички в виде строки
*/
private void serializeTagsPage(String dataPage) throws IOException {
notifyListeners(Utils.HANDLE_PROGRESS);
Document rootNode = Jsoup.parse(dataPage);
UserData.getInstance().updateData(rootNode);
notifyListeners(Utils.HANDLE_UPDATE_HEADERS);
TagsPage scannedTags = new TagsPage(mNetworkClient.getCurrentUrl());
Element diaryTag = rootNode.select("#authorName").first();
if (diaryTag != null) {
String Id = diaryTag.getElementsByTag("a").last().attr("href");
scannedTags.setDiaryId(Id.substring(Id.lastIndexOf("?") + 1));
}
notifyListeners(Utils.HANDLE_PROGRESS_2);
Elements effectiveAreas = rootNode.select("ul.tags_ul_all");
if (effectiveAreas.isEmpty()) // Нет вообще никаких тэгов, заканчиваем
return;
Elements result = effectiveAreas.clone();
Document resultPage = Document.createShell(mNetworkClient.getCurrentUrl());
resultPage.title(rootNode.title());
for (Element to : result) {
resultPage.body().appendChild(to);
}
mutateContent(resultPage);
scannedTags.setContent(resultPage.html());
scannedTags.setTitle(resultPage.title());
UserData.getInstance().setCurrentDiaryPage(scannedTags);
}
/**
* Страничка дискуссий, напр. http://www.diary.ru/discussion/
* @param dataPage html-контент странички в виде строки
*/
private void serializeDiscussionsPage(String dataPage) {
notifyListeners(Utils.HANDLE_PROGRESS);
Document rootNode = Jsoup.parse(dataPage);
UserData.getInstance().updateData(rootNode);
notifyListeners(Utils.HANDLE_UPDATE_HEADERS);
DiscussionList dList = new DiscussionList(mNetworkClient.getCurrentUrl());
List<DiscPage> pages = new ArrayList<>();
notifyListeners(Utils.HANDLE_PROGRESS_2);
Element dIndex = rootNode.getElementById("all_bits");
for (Element item : dIndex.getElementsByTag("h3")) {
DiscPage currentList = new DiscPage();
Element newPosts = item.getElementsByTag("em").first();
currentList.setLastUpdate(newPosts.text());
newPosts.remove();
String link = item.getElementsByAttributeValueStarting("href", "/discussion/?open[]").attr("href") + "&js";
currentList.setURL(link);
String title = item.text();
currentList.setTitle(title);
pages.add(currentList);
}
dList.setTitle(rootNode.title());
dList.setDiscussions(pages);
UserData.getInstance().setCurrentDiaryPage(dList);
}
/**
* JS-ответ на запрос дискуссий
* @param dataPage html-контент ответа в виде строки
*/
private void serializeDiscussions(String dataPage, ArrayList<DiscPage.Discussion> destination) {
destination.clear();
dataPage = dataPage.replace("\\\"", "\"");
Document rootNode = Jsoup.parse(dataPage);
Elements tables = rootNode.getElementsByTag("em");
tables.remove();
for (Element discussion : rootNode.getElementsByTag("a")) {
DiscPage.Discussion currentDisc = new DiscPage.Discussion();
currentDisc.url = discussion.attr("href");
currentDisc.title = discussion.text();
currentDisc.date = discussion.previousElementSibling().text();
destination.add(currentDisc);
}
}
/**
* Страничка списка U-mail, напр. http://www.diary.ru/u-mail/folder/?f_id=1
* @param dataPage html-контент странички в виде строки
*/
private void serializeUmailListPage(String dataPage) {
notifyListeners(Utils.HANDLE_PROGRESS);
Document rootNode = Jsoup.parse(dataPage);
UserData.getInstance().updateData(rootNode);
notifyListeners(Utils.HANDLE_UPDATE_HEADERS);
UserData.getInstance().setCurrentUmails(new DiaryLinkList<UmailListPage>(mNetworkClient.getCurrentUrl()));
Element table = rootNode.select("table.table.l").first();
if (table == null) // Нет вообще никаких сообщений, заканчиваем
return;
Element pages = rootNode.select("table.pages").first();
if (pages != null)
UserData.getInstance().getCurrentUmails().setPageLinks(Html.fromHtml(pages.outerHtml()));
Elements rows = table.select("tr[id]");
Element title = null, author = null, lastPost = null;
for (Element row : rows) {
if (title == null)
title = row.getElementsByClass("withfloat").first();
if (author == null)
author = row.select("[target=_blank]").first();
if (lastPost == null)
lastPost = row.getElementsByClass("r").first();
if (title != null && author != null && lastPost != null) {
UmailListPage mail = new UmailListPage();
mail.setTitle(title.getElementsByTag("b").text());
mail.setURL(title.attr("href"));
mail.setAuthor(author.text());
String authorData = author.attr("href");
//mail.setAuthorURL(authorData);
mail.setAuthorID(authorData.substring(authorData.lastIndexOf("?") + 1));
mail.setLastUpdate(lastPost.text());
mail.setLastUpdateUrl(lastPost.attr("href"));
Element preview = row.select("span.flwin").first();
if(preview != null)
mail.setPageHint(preview.text());
mail.setRead(!row.hasClass("not_readed_umail"));
UserData.getInstance().getCurrentUmails().add(mail);
title = author = lastPost = null;
}
}
}
/**
* Страничка просмотра U-mail, напр. http://www.diary.ru/u-mail/read/?u_id=320286777
* @param dataPage html-контент странички в виде строки
*/
private void serializeUmailPage(String dataPage) {
notifyListeners(Utils.HANDLE_PROGRESS);
Document rootNode = Jsoup.parse(dataPage);
UserData.getInstance().updateData(rootNode);
notifyListeners(Utils.HANDLE_UPDATE_HEADERS);
UmailPage scannedUmail = new UmailPage(mNetworkClient.getCurrentUrl());
notifyListeners(Utils.HANDLE_PROGRESS_2);
Elements mailArea = rootNode.select("table.box, table.box + div");
if (mailArea.isEmpty()) // Нет вообще никаких постов, заканчиваем
return;
Element sender = mailArea.select("div[style^=float:left] > b").first();
if (sender != null)
scannedUmail.setSenderName(sender.text());
Element theme = mailArea.select("tbody td").last();
if (theme != null)
scannedUmail.setMessageTheme(theme.text());
Elements result = mailArea.clone();
Document resultPage = Document.createShell(mNetworkClient.getCurrentUrl());
resultPage.title(rootNode.title());
for (Element to : result)
resultPage.body().appendChild(to);
mutateContent(resultPage);
scannedUmail.setContent(resultPage.html());
scannedUmail.setTitle(resultPage.title());
UserData.getInstance().setCurrentUmailPage(scannedUmail);
}
/**
* Функция для применения модификаций ко всем загружаемым страницам дневников
* Сюда вносятся правки страниц по просьбам пользователей
* @param resultPage страница, которую нужно модифицировать
*/
private void mutateContent(Document resultPage) {
// страница будет иметь наш стиль
String theme = mPreferences.getString("app.theme", "red");
resultPage.head().append("<link rel=\"stylesheet\" href=\"file:///android_asset/css/" + theme + ".css\" type=\"text/css\" media=\"all\" title=\"Стандарт\"/>");
// кнопка репоста указывает на нужную ссылку
Elements shareLinks = resultPage.select(".postLinks li[class^=quote]");
for (Element shareLi : shareLinks) {
if (shareLi.childNodeSize() == 0)
continue;
Element repostLink = shareLi.child(0);
Element diaryRepost = shareLi.select("div a[href*=newpost]").first();
if (diaryRepost != null)
repostLink.attr("href", diaryRepost.attr("href"));
}
// текст вместо кнопок правки
if(mUseTextInsteadOfImages) {
Elements postActionImages = resultPage.select("ul.postActionLinks img");
for (Element img : postActionImages) { // переделываем на текст
if (img.hasAttr("title")) {
Node text = new TextNode(img.attr("title"), resultPage.baseUri());
img.replaceWith(text);
}
}
}
// правка JS
Elements jsElems = resultPage.getElementsByAttribute("onclick");
for (Element js : jsElems) {
String link = js.attr("href");
if (!link.contains("#more") && !link.contains("subscribe") && !link.contains("showresult") &&
!link.contains("up&signature=") && !link.contains("down&signature=") &&
!link.contains("tag_showedit"))
js.removeAttr("onclick"); // Убиваем весь яваскрипт кроме MORE, поднятия/опускания постов, результатов голосования и подписки
}
// смена картинок, если автозагрузка выключена
if (!mLoadImages) {
Elements images = resultPage.select("img[src^=http], a:has(img)");
for (Element current : images) {
if (current.tagName().equals("img")) {
String src = current.attr("src");
if (!src.contains("diary.ru") && !current.parent().className().equals("avatar") && !src.startsWith("/")) {
// все неподходящие под критерии изображения на странице будут заменены на кнопки, по клику на которые и будут открываться
String jsButton = "<input type='image' src='file:///android_asset/images/load_image.png' onclick='return handleIMGDown(this, \"" + src + "\")' />";
current.after(jsButton);
current.remove();
}
}
if (current.tagName().equals("a")) {
String src = current.getElementsByTag("img").attr("src");
if (!src.contains("diary.ru") && !current.parent().className().equals("avatar") && !src.startsWith("/")) {
// все неподходящие под критерии изображения на странице будут заменены на кнопки, по клику на которые и будут открываться
String jsButton = "<input type='image' src='file:///android_asset/images/load_image.png' onclick='return handleADown(this, \"" + current.attr("href") + "\", \"" + src + "\")' />";
current.after(jsButton);
current.remove();
}
}
}
}
// включаем джаваскрипт
resultPage.body().append(Utils.javascriptContent);
// сигнатура должна быть видна методам JS
resultPage.body().append("<script>var signature = '" + UserData.getInstance().getSignature() + "';</script>");
}
// TODO: превратить этот метод в нормальную фабрику!
private void checkUrlAndHandle(String requestedUrl, boolean reload) {
Class<?> handled;
Object cachedPage = null;
String dataPage = null;
try {
URI toLoad = mNetworkClient.resolve(requestedUrl);
boolean isNewPage = shouldReloadUrl(toLoad);
// загружаем из кэша, если это не новый коммент и не запрос на перезагрузку
if (mCache.hasPage(toLoad) && !reload && !isNewPage) {
cachedPage = mCache.loadPageFromCache(toLoad);
handled = cachedPage.getClass();
} else {
final Response page = mNetworkClient.getPage(toLoad);
if(page == null || !page.isSuccessful()) { // no response, may be ssl error
notifyListeners(Utils.HANDLE_CONNECTIVITY_ERROR, R.string.connection_error);
return;
}
// проверим, не картинка ли это
if (page.body().contentType().type().equals("image")) { // Just load image, no further processing
if (reload) { // reload - save
String srcName = page.header("Content-Disposition");
final String realName = URLUtil.guessFileName(requestedUrl, srcName, MimeTypeMap.getFileExtensionFromUrl(requestedUrl));
CacheManager.saveDataToSD(getApplicationContext(), realName, page.body().bytes());
} else // no reload - open
notifyListeners(Utils.HANDLE_GET_WEB_PAGE_DATA, requestedUrl);
return;
}
dataPage = page.body().string();
handled = Utils.checkDiaryUrl(dataPage);
if (dataPage.contains("box-error") || dataPage.contains("попробовать что-нибудь еще")) { // неопознанная страничка
notifyListeners(Utils.HANDLE_CONNECTIVITY_ERROR, R.string.closed_error); // если наткнулись на ошибку дневника
return;
}
}
if (handled == null) { // Если это не страничка дайри
notifyListeners(Utils.HANDLE_CONNECTIVITY_ERROR, R.string.page_incorrect);
return;
}
mNetworkClient.setCurrentUrl(toLoad);
if (cachedPage != null) { // если страничка была в кэше или из числа новых комментов
if (cachedPage instanceof DiaryLinkList) {
// umail-варианты сюда не попадают, их путь не идёт через checkDiaryUrl
//noinspection unchecked
UserData.getInstance().setCurrentDiaries((DiaryLinkList<ListPage>) cachedPage);
notifyListeners(Utils.HANDLE_GET_LIST_PAGE_DATA);
}
if (cachedPage instanceof DiscussionList) {
UserData.getInstance().setCurrentDiaryPage((WebPage) cachedPage);
notifyListeners(Utils.HANDLE_GET_DISCUSSIONS_DATA);
}
if (cachedPage instanceof WebPage) {
UserData.getInstance().setCurrentDiaryPage((WebPage) cachedPage);
notifyListeners(Utils.HANDLE_GET_WEB_PAGE_DATA);
}
return;
}
// если нет такого кэша
if (handled == DiaryPage.class) {
serializeDiaryPage(dataPage);
mCache.putPageToCache(toLoad, UserData.getInstance().getCurrentDiaryPage());
notifyListeners(Utils.HANDLE_GET_WEB_PAGE_DATA);
} else if (handled == CommentsPage.class) {
serializeCommentsPage(dataPage);
mCache.putPageToCache(toLoad, UserData.getInstance().getCurrentDiaryPage());
notifyListeners(Utils.HANDLE_GET_WEB_PAGE_DATA);
} else if (handled == TagsPage.class) {
serializeTagsPage(dataPage);
mCache.putPageToCache(toLoad, UserData.getInstance().getCurrentDiaryPage());
notifyListeners(Utils.HANDLE_GET_WEB_PAGE_DATA);
} else if (handled == DiaryProfilePage.class) {
serializeProfilePage(dataPage);
mCache.putPageToCache(toLoad, UserData.getInstance().getCurrentDiaryPage());
notifyListeners(Utils.HANDLE_GET_WEB_PAGE_DATA);
} else if (handled == DiaryLinkList.class) {
serializeDiaryListPage(dataPage);
mCache.putPageToCache(toLoad, UserData.getInstance().getCurrentDiaries());
notifyListeners(Utils.HANDLE_GET_LIST_PAGE_DATA);
} else if (handled == DiscussionList.class) {
serializeDiscussionsPage(dataPage);
mCache.putPageToCache(toLoad, UserData.getInstance().getCurrentDiaryPage());
notifyListeners(Utils.HANDLE_GET_DISCUSSIONS_DATA);
} else if (handled == SearchPage.class) {
serializeSearchPage(dataPage);
mCache.putPageToCache(toLoad, UserData.getInstance().getCurrentDiaryPage());
notifyListeners(Utils.HANDLE_GET_WEB_PAGE_DATA);
}
} catch (NullPointerException | IllegalArgumentException e) {
notifyListeners(Utils.HANDLE_CONNECTIVITY_ERROR, R.string.page_incorrect);
} catch (InterruptedIOException e) {
notifyListeners(Utils.HANDLE_CONNECTIVITY_ERROR, R.string.canceled);
} catch (IOException e) {
if(e.getMessage() != null && e.getMessage().contains("closed")) {
notifyListeners(Utils.HANDLE_CONNECTIVITY_ERROR, R.string.canceled);
} else {
notifyListeners(Utils.HANDLE_CONNECTIVITY_ERROR, R.string.connection_error);
}
}
}
private boolean shouldReloadUrl(URI toLoad) {
if(!UserData.getInstance().hasNotifications()) { // предварительная проверка
return false;
}
if(UserData.getInstance().getNewDiscussNum() > 0) { // если у нас есть новая дискуссия, нужно перезагрузить её
URI newDiscussion = mNetworkClient.resolve(UserData.getInstance().getNewDiscussLink());
if(TextUtils.equals(newDiscussion.getPath(), toLoad.getPath())) {
return true;
}
}
if(UserData.getInstance().getNewDiaryCommentsNum() > 0) { // если у нас есть новый коммент в дневнике...
URI newDiaryComment = mNetworkClient.resolve(UserData.getInstance().getNewDiaryLink());
if(TextUtils.equals(newDiaryComment.getPath(), toLoad.getPath())) {
return true;
}
}
return false;
}
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
switch (key) {
case SHARED_PROP_IMAGES_AUTOLOAD:
mLoadImages = sharedPreferences.getBoolean(key, false);
break;
case SHARED_PROP_SERVICE_NOTIFY_UPDATES:
mHandler.removeMessages(Utils.HANDLE_SERVICE_UPDATE);
mNotifyOnUpdates = sharedPreferences.getBoolean(key, false);
if (mNotifyOnUpdates)
mHandler.sendMessageDelayed(mHandler.obtainMessage(Utils.HANDLE_SERVICE_UPDATE), 300000);
break;
case SHARED_PROP_SERVICE_KEEP_DEVICE_ON:
if (mWakeLock.isHeld())
mWakeLock.release();
mKeepDeviceOn = sharedPreferences.getBoolean(key, false);
if (mKeepDeviceOn)
mWakeLock.acquire();
break;
case SHARED_PROP_SERVICE_ALWAYS_RUNNING:
mIsStickyService = sharedPreferences.getBoolean(key, false);
if (mIsStickyService)
startForeground(NOTIFICATION_ID, createNotification(UserData.getInstance().getCurrentDiaryPage()));
else
stopForeground(true);
break;
case SHARED_PROP_WEBVIEW_FONT_SIZE:
for (DiaryActivity current : mListeners)
current.handleFontChange(sharedPreferences.getString(SHARED_PROP_WEBVIEW_FONT_SIZE, "12"));
break;
case SHARED_PROP_PRELOAD_THEMES:
mPreloadThemes = sharedPreferences.getBoolean("preload.themes", true);
break;
case SHARED_PROP_PRELOAD_UMAIL_QUOTING:
mPreloadUmails = sharedPreferences.getBoolean("preload.umail.quoting", true);
break;
case SHARED_PROP_USE_TEXT_LINKS:
mUseTextInsteadOfImages = sharedPreferences.getBoolean(SHARED_PROP_USE_TEXT_LINKS, false);
break;
case SHARED_PROP_SCREEN_ORIENTATION:
mOrientation = Integer.parseInt(sharedPreferences.getString("screen.orientation", "-1"));
break;
case SHARED_PROP_NEW_ON_NOTIFICATION_CLICK:
mOpenNewLinkOnNotificationClick = sharedPreferences.getBoolean(SHARED_PROP_NEW_ON_NOTIFICATION_CLICK, true);
break;
}
}
// Создаем уведомление в статусной строке - для принудительно живого сервиса в Foreground-режиме
private Notification createNotification(WebPage page) {
NotificationCompat.Builder nBuilder = new NotificationCompat.Builder(this);
nBuilder.setContentTitle(getString(R.string.service_notification));
nBuilder.setContentText(page.getContent() != null && page.getTitle() != null ? page.getTitle() : "");
nBuilder.setSmallIcon(R.drawable.ic_launcher_status_icon);
nBuilder.setLargeIcon(mNotificationIcon);
nBuilder.setOngoing(true);
final Intent intent = new Intent(this, DiaryListActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
nBuilder.setContentIntent(PendingIntent.getActivity(this, 0, intent, 0));
return nBuilder.build();
}
public void newSession() {
UserData.clear();
mNetworkClient.getCookieStore().removeAll();
mCache.clear();
}
private static class NotifyState {
private String lastDiaryLink = "";
private String lastDiscussionLink = "";
private String lastUmailLink = "";
public boolean shouldNotify(UserData user) {
return !lastDiaryLink.equals(user.getNewDiaryLink()) ||
!lastDiscussionLink.equals(user.getNewDiscussLink()) ||
!lastUmailLink.equals(user.getNewUmailLink());
}
}
}