-
-
Save creativetrendsapps/da211dd75cfb4af4cb79 to your computer and use it in GitHub Desktop.
Notifications with messages
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.creativtrendz.folio.notifications; | |
import android.annotation.SuppressLint; | |
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.res.Resources; | |
import android.graphics.BitmapFactory; | |
import android.graphics.Color; | |
import android.net.Uri; | |
import android.os.AsyncTask; | |
import android.os.Build; | |
import android.os.Handler; | |
import android.os.HandlerThread; | |
import android.os.IBinder; | |
import android.os.Looper; | |
import android.support.v4.app.NotificationCompat; | |
import android.util.Log; | |
import android.webkit.CookieManager; | |
import android.webkit.CookieSyncManager; | |
import android.widget.Toast; | |
import com.creativetrends.folio.app.key.R; | |
import com.creativtrendz.folio.activities.FolioApplication; | |
import com.creativtrendz.folio.activities.MainActivity; | |
import com.creativtrendz.folio.services.Connectivity; | |
import com.creativtrendz.folio.utils.Logger; | |
import net.grandcentrix.tray.TrayAppPreferences; | |
import org.jsoup.Jsoup; | |
import org.jsoup.nodes.Element; | |
import org.jsoup.select.Elements; | |
import java.io.IOException; | |
public class FolioNotifications extends Service { | |
private static final String BASE_URL = "https://mobile.facebook.com"; | |
private static final String NOTIFICATIONS_URL = "https://m.facebook.com/notifications.php"; | |
private static final String NOTIFICATIONS_URL_BACKUP = "https://mobile.facebook.com/notifications.php"; | |
private static final String MESSAGES_URL = "https://m.facebook.com/messages"; | |
private static final String MESSAGES_URL_BACKUP = "https://mobile.facebook.com/messages"; | |
private static String NOTIFICATION_MESSAGE_URL = "https://m.facebook.com/messages#"; | |
private Context context = this; | |
private static final int MAX_RETRY = 3; | |
private static final int JSOUP_TIMEOUT = 10000; | |
private static final String TAG; | |
private final HandlerThread handlerThread; | |
private final Handler handler; | |
private static Runnable runnable; | |
private volatile boolean shouldContinue = true; | |
private static String userAgent; | |
private TrayAppPreferences trayPreferences; | |
private final Logger Log; | |
static { | |
TAG = FolioNotifications.class.getSimpleName(); | |
} | |
public FolioNotifications() { | |
handlerThread = new HandlerThread("Handler Thread"); | |
handlerThread.start(); | |
handler = new Handler(handlerThread.getLooper()); | |
Log = Logger.getInstance(); | |
} | |
@Override | |
public IBinder onBind(Intent intent) { | |
return null; | |
} | |
@Override | |
public void onCreate() { | |
Log.i(TAG, "********** Service created! **********"); | |
super.onCreate(); | |
trayPreferences = new TrayAppPreferences(getApplicationContext()); | |
runnable = new HandlerRunnable(); | |
handler.postDelayed(runnable, 3000); | |
long now = System.currentTimeMillis(); | |
long sinceLastCheck = now - trayPreferences.getLong("last_check", now); | |
} | |
@Override | |
public int onStartCommand(Intent intent, int flags, int startId) { | |
return START_STICKY; | |
} | |
@Override | |
public void onDestroy() { | |
Log.i(TAG, "onDestroy: Service stopping..."); | |
super.onDestroy(); | |
synchronized (handler) { | |
shouldContinue = false; | |
handler.notify(); | |
} | |
handler.removeCallbacksAndMessages(null); | |
handlerThread.quit(); | |
} | |
/** A runnable used by the Handler to schedule checking. */ | |
private class HandlerRunnable implements Runnable { | |
public void run() { | |
try { | |
final int timeInterval = trayPreferences.getInt("interval_pref", 1800000); | |
Log.i(TAG, "Time interval: " + (timeInterval / 1000) + " seconds"); | |
final long now = System.currentTimeMillis(); | |
final long sinceLastCheck = now - trayPreferences.getLong("last_check", now); | |
final boolean ntfLastStatus = trayPreferences.getBoolean("ntf_last_status", false); | |
final boolean msgLastStatus = trayPreferences.getBoolean("msg_last_status", false); | |
if ((sinceLastCheck < timeInterval) && ntfLastStatus && msgLastStatus) { | |
final long waitTime = timeInterval - sinceLastCheck; | |
if (waitTime >= 1000) { | |
Log.i(TAG, "I'm going to wait. Resuming in: " + (waitTime / 1000) + " seconds"); | |
synchronized (handler) { | |
try { | |
handler.wait(waitTime); | |
} catch (InterruptedException ex) { | |
Log.i(TAG, "Thread interrupted"); | |
} finally { | |
Log.i(TAG, "Lock is now released"); | |
} | |
} | |
} | |
} | |
if (shouldContinue) { | |
if (Connectivity.isConnected(getApplicationContext())) { | |
Log.i(TAG, "Internet connection active. Starting AsyncTasks..."); | |
String connectionType = "Wi-Fi"; | |
if (Connectivity.isConnectedMobile(getApplicationContext())) | |
connectionType = "Mobile"; | |
Log.i(TAG, "Connection Type: " + connectionType); | |
userAgent = trayPreferences.getString("webview_user_agent", System.getProperty("http.agent")); | |
Log.i(TAG, "User Agent: " + userAgent); | |
if (trayPreferences.getBoolean("notifications_activated", false)) | |
new CheckNotificationsTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null); | |
if (trayPreferences.getBoolean("messages_activated", false)) | |
new CheckMessagesTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null); | |
trayPreferences.put("last_check", System.currentTimeMillis()); | |
} else | |
Log.i(TAG, "No internet connection. Skip checking."); | |
handler.postDelayed(runnable, timeInterval); | |
} else | |
Log.i(TAG, "Notified to stop running. Exiting..."); | |
} catch (RuntimeException re) { | |
Log.i(TAG, "RuntimeException caught"); | |
restartItself(); | |
} | |
} | |
} | |
/** Notifications checker task: it checks Facebook notifications only. */ | |
private class CheckNotificationsTask extends AsyncTask<Void, Void, Element> { | |
boolean syncProblemOccurred = false; | |
private Element getElement(String connectUrl) { | |
try { | |
return Jsoup.connect(connectUrl).userAgent(userAgent).timeout(JSOUP_TIMEOUT) | |
.cookie("https://mobile.facebook.com", CookieManager.getInstance().getCookie("https://mobile.facebook.com")).get() | |
.select("a.touchable").not("a._19no").not("a.button").first(); | |
} catch (IllegalArgumentException ex) { | |
Log.i("Facebook Notifications", "Cookie sync problem occurred"); | |
if (!syncProblemOccurred) { | |
syncProblemToast(); | |
syncProblemOccurred = true; | |
} | |
} catch (IOException ex) { | |
ex.printStackTrace(); | |
} | |
return null; | |
} | |
@Override | |
protected Element doInBackground(Void... params) { | |
Element result = null; | |
int tries = 0; | |
syncCookies(); | |
while (tries++ < MAX_RETRY && result == null) { | |
Log.i("Facebook Notifications", "Trying sync " + tries); | |
Log.i("Facebook Notifications", "Trying: " + MESSAGES_URL); | |
Element notif = getElement(NOTIFICATIONS_URL); | |
if (notif != null) { | |
result = notif; | |
} | |
} | |
return result; | |
} | |
@Override | |
protected void onPostExecute(Element result) { | |
try { | |
if (result == null) { | |
return; | |
} | |
if (result.text() == null) { | |
return; | |
} | |
if (!trayPreferences.getBoolean("activity_visible", false) || trayPreferences.getBoolean("notifications_everywhere", true)) { | |
notifier(result.text(), BASE_URL + result.attr("href"), false); | |
Log.i("Facebook Notifications", "Starting sync"); | |
} | |
trayPreferences.put("ntf_last_status", true); | |
Log.i("CheckMessagesTask", "onPostExecute: Aight biatch ;)"); | |
} catch (NumberFormatException ex) { | |
trayPreferences.put("ntf_last_status", false); | |
Log.i("CheckMessagesTask", "onPostExecute: Failure"); | |
} | |
} | |
} | |
/** Messages checker task: it checks new messages only. */ | |
private class CheckMessagesTask extends AsyncTask<Void, Void, String> { | |
boolean syncProblemOccurred = false; | |
private String getNumber(String connectUrl) { | |
try { | |
Elements message = Jsoup.connect(connectUrl).userAgent(userAgent).timeout(JSOUP_TIMEOUT) | |
.cookie("https://m.facebook.com", CookieManager.getInstance().getCookie("https://m.facebook.com")).get() | |
.select("div#viewport").select("div#page").select("div._129-") | |
.select("#messages_jewel").select("span._59tg"); | |
return message.html(); | |
} catch (IllegalArgumentException ex) { | |
Log.i("CheckMessagesTask", "Cookie sync problem occurred"); | |
if (!syncProblemOccurred) { | |
syncProblemToast(); | |
syncProblemOccurred = true; | |
} | |
} catch (IOException ex) { | |
ex.printStackTrace(); | |
} | |
return "failure"; | |
} | |
@Override | |
protected String doInBackground(Void... params) { | |
String result = null; | |
int tries = 0; | |
syncCookies(); | |
while (tries++ < MAX_RETRY && result == null) { | |
Log.i("CheckMessagesTask", "doInBackground: Processing... Trial: " + tries); | |
Log.i("CheckMsgTask:getNumber", "Trying: " + MESSAGES_URL); | |
String number = getNumber(MESSAGES_URL); | |
if (!number.matches("^[+-]?\\d+$")) { | |
Log.i("CheckMsgTask:getNumber", "Trying: " + MESSAGES_URL_BACKUP); | |
number = getNumber(MESSAGES_URL_BACKUP); | |
} | |
if (number.matches("^[+-]?\\d+$")) | |
result = number; | |
} | |
return result; | |
} | |
@SuppressLint("StringFormatInvalid") | |
@Override | |
protected void onPostExecute(String result) { | |
try { | |
int newMessages = Integer.parseInt(result); | |
if (!trayPreferences.getBoolean("activity_visible", false) || trayPreferences.getBoolean("notifications_everywhere", true)) { | |
if (newMessages == 1) | |
notifier(getString(R.string.you_have_one_message), NOTIFICATION_MESSAGE_URL, true); | |
else if (newMessages > 1) | |
notifier(String.format(getString(R.string.you_have_n_messages), newMessages), NOTIFICATION_MESSAGE_URL, true); | |
} | |
trayPreferences.put("msg_last_status", true); | |
Log.i("CheckMessagesTask", "onPostExecute: Aight biatch ;)"); | |
} catch (NumberFormatException ex) { | |
trayPreferences.put("msg_last_status", false); | |
Log.i("CheckMessagesTask", "onPostExecute: Failure"); | |
} | |
} | |
} | |
/** CookieSyncManager was deprecated in API level 21. | |
* We need it for API level lower than 21 though. | |
* In API level >= 21 it's done automatically. | |
*/ | |
@SuppressWarnings("deprecation") | |
private void syncCookies() { | |
if (Build.VERSION.SDK_INT < 21) { | |
CookieSyncManager.createInstance(getApplicationContext()); | |
CookieSyncManager.getInstance().sync(); | |
} | |
} | |
private void syncProblemToast() { | |
Handler handler = new Handler(Looper.getMainLooper()); | |
handler.post(new Runnable() { | |
@Override | |
public void run() { | |
Toast.makeText(getApplicationContext(), getString(R.string.sync_problem), | |
Toast.LENGTH_SHORT).show(); | |
} | |
}); | |
} | |
private void restartItself() { | |
final Context context = FolioApplication.getContextOfApplication(); | |
final Intent intent = new Intent(context, FolioNotifications.class); | |
context.stopService(intent); | |
context.startService(intent); | |
} | |
@SuppressWarnings("deprecation") | |
@SuppressLint("InlinedApi") | |
private void notifier(String notificationText, String url, boolean isMessage) { | |
Log.i(TAG, "Start notification - isMessage: " + isMessage); | |
@SuppressWarnings("deprecation") | |
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this); | |
mBuilder.setContentTitle(getResources().getString(R.string.app_name)); | |
mBuilder.setContentText(notificationText); | |
mBuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(notificationText)); | |
mBuilder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher)); | |
mBuilder.setColor(getResources().getColor(R.color.PrimaryDarkColor)); | |
mBuilder.setTicker(notificationText); | |
mBuilder.setWhen(System.currentTimeMillis()); | |
String ringtoneKey = "ringtone"; | |
if (isMessage) | |
ringtoneKey = "ringtone_msg"; | |
Uri ringtoneUri = Uri.parse(trayPreferences.getString(ringtoneKey, "content://settings/system/notification_sound")); | |
mBuilder.setSound(ringtoneUri); | |
if (trayPreferences.getBoolean("vibrate", false)) | |
mBuilder.setVibrate(new long[]{500, 500}); | |
else | |
mBuilder.setVibrate(new long[]{0L}); | |
if (trayPreferences.getBoolean("led_light", false)) { | |
Resources resources = getResources(), systemResources = Resources.getSystem(); | |
mBuilder.setLights(Color.CYAN, | |
resources.getInteger(systemResources.getIdentifier("config_defaultNotificationLedOn", "integer", "android")), | |
resources.getInteger(systemResources.getIdentifier("config_defaultNotificationLedOff", "integer", "android"))); | |
} | |
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) | |
mBuilder.setPriority(Notification.PRIORITY_HIGH); | |
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); | |
if (!isMessage) { | |
Intent actionIntent = new Intent(this, MainActivity.class); | |
actionIntent.putExtra("start_url", url); | |
actionIntent.setAction("NOTIFICATION_URL_ACTION"); | |
PendingIntent pendingMessageIntent = PendingIntent.getActivity(this, 0, actionIntent, PendingIntent.FLAG_UPDATE_CURRENT); | |
mBuilder.setSmallIcon(R.drawable.ic_public); | |
mBuilder.setColor(getResources().getColor(R.color.PrimaryDarkColor)); | |
mBuilder.setContentIntent(pendingMessageIntent); | |
mBuilder.setOngoing(false); | |
Notification notification = mBuilder.build(); | |
notificationManager.notify(0, notification); | |
} else { | |
Intent messageIntent = new Intent(this, MainActivity.class); | |
messageIntent.putExtra("start_url", NOTIFICATION_MESSAGE_URL); | |
PendingIntent pendingMessageIntent = PendingIntent.getActivity(this, 1, messageIntent, PendingIntent.FLAG_UPDATE_CURRENT); | |
mBuilder.setSmallIcon(R.drawable.ic_messenger_new); | |
mBuilder.setColor(getResources().getColor(R.color.PrimaryDarkColor)); | |
mBuilder.setContentIntent(pendingMessageIntent); | |
mBuilder.setOngoing(false); | |
Notification message = mBuilder.build(); | |
notificationManager.notify(1, message); | |
} | |
} | |
public static void clearNotifications() { | |
NotificationManager notificationManager = (NotificationManager) | |
FolioApplication.getContextOfApplication().getSystemService(Context.NOTIFICATION_SERVICE); | |
notificationManager.cancel(0); | |
} | |
public static void clearMessages() { | |
NotificationManager notificationManager = (NotificationManager) | |
FolioApplication.getContextOfApplication().getSystemService(Context.NOTIFICATION_SERVICE); | |
notificationManager.cancel(1); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment