package com.abewy.android.apps.klyph.service;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import android.app.Service;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.support.v4.app.NotificationCompat.Builder;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import com.abewy.android.apps.klyph.KlyphBundleExtras;
import com.abewy.android.apps.klyph.KlyphNotification;
import com.abewy.android.apps.klyph.KlyphPreferences;
import com.abewy.android.apps.klyph.R;
import com.abewy.android.apps.klyph.core.KlyphDevice;
import com.abewy.android.apps.klyph.core.fql.Notification;
import com.abewy.android.apps.klyph.core.graph.GraphObject;
import com.abewy.android.apps.klyph.core.imageloader.ImageLoader;
import com.abewy.android.apps.klyph.core.imageloader.SimpleFakeImageLoaderListener;
import com.abewy.android.apps.klyph.core.request.Response;
import com.abewy.android.apps.klyph.request.AsyncRequest;
import com.abewy.android.apps.klyph.request.AsyncRequest.Query;
import com.crashlytics.android.Crashlytics;
import com.facebook.Session;
import com.squareup.picasso.Picasso.LoadedFrom;
public class NotificationService extends Service
{
private static final String TAG = "NotificationService";
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
@Override
public void onCreate()
{
// Why initialize device values ?
// Because we need the density to calculate image size
// In notification request
KlyphDevice.initDeviceValues(this);
HandlerThread thread = new HandlerThread("ServiceStartArguments", android.os.Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper, new WeakReference<Service>(this));
}
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
// If we get killed, after returning from here, restart
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent)
{
// We don't provide binding, so return null
return null;
}
@Override
public void onDestroy()
{
}
// Handler that receives messages from the thread
private static final class ServiceHandler extends Handler
{
private final WeakReference<Service> service;
public ServiceHandler(Looper looper, WeakReference<Service> service)
{
super(looper);
this.service = service;
}
@Override
public void handleMessage(Message msg)
{
launchRequest();
Intent intent = new Intent(KlyphBundleExtras.NOTIFICATION_EVENT);
// Add data
intent.putExtra(KlyphBundleExtras.NOTIFICATION_EVENT_DATA, "test broadcast");
LocalBroadcastManager.getInstance(service.get()).sendBroadcast(intent);
// Force a reload of the notification pane even if there isn't any update
KlyphPreferences.setNotificationReadStatusChanged(true);
}
private void launchRequest()
{
Log.d("NotificationService.ServiceHandler", "launchRequest: ");
if (service.get() == null)
return;
try
{
if (Session.getActiveSession() == null)
{
Session.openActiveSessionFromCache(service.get());
}
}
catch (UnsupportedOperationException e)
{
Log.d("NotificationService.ServiceHandler", "launchRequest: exception " + e.getMessage());
}
if (Session.getActiveSession() != null && Session.getActiveSession().getPermissions().contains("manage_notifications"))
{
AsyncRequest request = new AsyncRequest(Query.PERIODIC_NOTIFICATIONS, "me()",
/*KlyphPreferences.getNotificationServiceOffset()*/"", new AsyncRequest.Callback() {
@Override
public void onComplete(Response response)
{
if (response.getError() == null)
{
onRequestSuccess(response.getGraphObjectList());
}
else
{
if (service.get() != null)
service.get().stopSelf();
}
}
});
request.execute();
}
else
{
if (service.get() != null)
service.get().stopSelf();
}
}
private void onRequestSuccess(List<GraphObject> list)
{
Log.d("NotificationService.ServiceHandler", "onRequestSuccess: " + list.size());
if (service.get() == null)
return;
if (list.size() > 0)
{
boolean notifyAppRequests = KlyphPreferences.notifyAppRequests();
boolean notifyAlbums = KlyphPreferences.notifyAlbums();
boolean notifyEvents = KlyphPreferences.notifyEvents();
boolean notifyFriends = KlyphPreferences.notifyFriendRequest();
boolean notifyGroups = KlyphPreferences.notifyGroups();
boolean notifyPages = KlyphPreferences.notifyPages();
boolean notifyPhotos = KlyphPreferences.notifyPhotos();
boolean notifyPokes = KlyphPreferences.notifyPokes();
boolean notifyStreams = KlyphPreferences.notifyStreams();
boolean notifyVideos = KlyphPreferences.notifyVideos();
List<Notification> filteredNotifications = new ArrayList<Notification>();
List<String> types = new ArrayList<String>();
types.add(Notification.TYPE_ALBUM);
types.add(Notification.TYPE_APP_REQUEST);
types.add(Notification.TYPE_COMMENT);
types.add(Notification.TYPE_EVENT);
types.add(Notification.TYPE_CANCELED_EVENT);
types.add(Notification.TYPE_FRIEND);
types.add(Notification.TYPE_GROUP);
types.add(Notification.TYPE_PAGE);
types.add(Notification.TYPE_PHOTO);
types.add(Notification.TYPE_POKE);
types.add(Notification.TYPE_STREAM);
types.add(Notification.TYPE_VIDEO);
types.add(Notification.TYPE_WEB_APP);
types.add(Notification.TYPE_USER);
boolean mustGroup = KlyphPreferences.mustGroupNotifications();
long lastCheckedTime = KlyphPreferences.getLastCheckedNotificationTime();
for (GraphObject graphObject : list)
{
Notification n = (Notification) graphObject;
String objectType = n.getObject_type();
// Trying to discover unreferenced types
if (!types.contains(objectType))
{
Crashlytics.setString("Notification_type ", objectType);
Crashlytics.setString("Object_name ", n.getObject_name());
Crashlytics.setString("Notification_text ", n.getTitle_text());
Crashlytics.setString("Notification_url ", n.getHref());
try
{
throw new Exception("NotificationService unknown notification type : " + objectType);
}
catch (Exception e)
{
Crashlytics.logException(e);
}
}
// Filtering
if (objectType.equals(Notification.TYPE_ALBUM) && notifyAlbums == false)
continue;
if (objectType.equals(Notification.TYPE_APP_REQUEST) && notifyAppRequests == false)
continue;
if ((objectType.equals(Notification.TYPE_EVENT) || objectType.equals(Notification.TYPE_CANCELED_EVENT)) && notifyEvents == false)
continue;
if ((objectType.equals(Notification.TYPE_FRIEND) || objectType.equals(Notification.TYPE_USER))&& notifyFriends == false)
continue;
if (objectType.equals(Notification.TYPE_GROUP) && notifyGroups == false)
continue;
if (objectType.equals(Notification.TYPE_PAGE) && notifyPages == false)
continue;
if (objectType.equals(Notification.TYPE_PHOTO) && notifyPhotos == false)
continue;
if (objectType.equals(Notification.TYPE_POKE) && notifyPokes == false)
continue;
if (objectType.equals(Notification.TYPE_STREAM) && notifyStreams == false)
continue;
if (objectType.equals(Notification.TYPE_VIDEO) && notifyVideos == false)
continue;
if (mustGroup)
{
// Add only if newer than last checked time
try
{
long time = Long.parseLong(n.getUpdated_time());
if (time > lastCheckedTime)
filteredNotifications.add(n);
}
catch (NumberFormatException e)
{
filteredNotifications.add(n);
}
}
else
{
filteredNotifications.add(n);
}
}
if (filteredNotifications.size() > 0)
{
sendNotifications(filteredNotifications);
}
else
{
service.get().stopSelf();
}
}
else
{
service.get().stopSelf();
}
}
private void sendNotifications(List<Notification> notifications)
{
Service s = service.get();
if (KlyphPreferences.mustGroupNotifications())
{
final Builder builder = KlyphNotification.getBuilder(service.get(), true);
if( notifications.size() > 1)
{
builder.setContentTitle(s.getString(R.string.app_large_name));
builder.setContentText(s.getString(R.string.new_notifications, notifications.size()));
builder.setTicker(s.getString(R.string.new_notifications, notifications.size()));
List<String> lines = new ArrayList<String>();
for (Notification notification : notifications)
{
lines.add(notification.getTitle_text());
}
KlyphNotification.setInboxStyle(builder, s.getString(R.string.app_large_name), lines);
KlyphNotification.sendNotification(s, builder);
}
else
{
sendNotification(notifications.get(0));
}
}
else
{
Collections.reverse(notifications);
for (Notification notification : notifications)
{
sendNotification(notification);
}
}
}
private void sendNotification(final Notification notification)
{
sendNotification(notification, true);
}
private void sendNotification(final Notification notification, final boolean sendDetails)
{
final Builder builder = KlyphNotification.getBuilder(service.get(), true);
builder.setContentTitle(notification.getSender_name());
builder.setContentText(notification.getTitle_text());
builder.setTicker(String.format("%1$s\n%2$s", notification.getSender_name(), notification.getTitle_text()));
ImageLoader.loadImage(notification.getSender_pic(), new SimpleFakeImageLoaderListener() {
@Override
public void onBitmapFailed(Drawable drawable)
{
if (sendDetails)
KlyphNotification.sendNotification(service.get(), builder, notification);
else
KlyphNotification.sendNotification(service.get(), builder);
}
@Override
public void onBitmapLoaded(Bitmap bitmap, LoadedFrom arg1)
{
builder.setLargeIcon(bitmap);
if (sendDetails)
KlyphNotification.sendNotification(service.get(), builder, notification);
else
KlyphNotification.sendNotification(service.get(), builder);
}
});
}
}
}