package net.qiujuer.tips.factory.service; import android.app.AlarmManager; import android.app.Application; import android.app.PendingIntent; import android.app.Service; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.support.annotation.StringRes; import com.google.gson.Gson; import net.qiujuer.tips.factory.model.Model; import net.qiujuer.tips.factory.model.adapter.ContactViewModel; import net.qiujuer.tips.factory.model.adapter.NewestModel; import net.qiujuer.tips.factory.model.adapter.RecordViewModel; import net.qiujuer.tips.factory.model.db.ContactModel; import net.qiujuer.tips.factory.model.db.RecordModel; import net.qiujuer.tips.factory.model.xml.SettingModel; import net.qiujuer.tips.factory.service.bean.MissServiceBean; import net.qiujuer.tips.factory.service.bean.MissWidgetListData; import net.qiujuer.tips.factory.service.network.Sync; import net.qiujuer.tips.factory.service.network.SyncCallback; import net.qiujuer.tips.factory.service.network.SyncChangeModel; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.List; import java.util.UUID; public class MissService extends Service { private final static String TAG = MissService.class.getName(); public final static String ACTION_MISS_MAIN = "net.qiujuer.tips.factory.service.MissService.MISS_MAIN"; public final static String ACTION_MISS_WIDGET = "net.qiujuer.tips.factory.service.MissService.MISS_WIDGET"; public final static String ACTION_MISS_WIDGET_VALUES = "VALUES"; public final static String ACTION_MISS_WIDGET_REFRESH = "net.qiujuer.tips.factory.service.MissService.MISS_WIDGET_REFRESH"; public final static String ACTION_MISS_SYNC = "net.qiujuer.tips.factory.service.MissService.MISS_SYNC"; public final static String ACTION_MISS_SYNC_VALUE_STATUS = "STATUS"; //public final static String ACTION_MISS_ALARM_RECEIVER = "android.intent.action.ALARM_RECEIVER"; //public final static String ACTION_MISS_ALARM_RECEIVER_REFRESH = "android.intent.action.ALARM_RECEIVER_REFRESH"; private static final int INTERVAL = 1000 * 60 * 60 * 24; private static final int DAY_COUNT = 5; private MissServiceImpl mBinder; private MissServiceBroadcastReceiver mReceiver; public static void start(Context context) { try { Intent serviceIntent = new Intent(context, MissService.class); context.startService(serviceIntent); } catch (Exception e) { e.printStackTrace(); } } @Override public void onCreate() { super.onCreate(); Model.log(TAG, "onCreate"); Application application = getApplication(); Model.setApplication(application); mBinder = new MissServiceImpl(application); mReceiver = new MissServiceBroadcastReceiver(); try { IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_MISS_WIDGET_REFRESH); //filter.addAction(ACTION_MISS_ALARM_RECEIVER_REFRESH); application.registerReceiver(mReceiver, filter); } catch (Exception e) { e.printStackTrace(); } // Register Alarm addAlarm(getApplication()); } @Override public int onStartCommand(Intent intent, int flags, int startId) { super.onStartCommand(intent, flags, startId); return START_STICKY; } @Override public void onDestroy() { MissServiceImpl binder = mBinder; mBinder = null; if (binder != null) { binder.destroy(); } MissServiceBroadcastReceiver receiver = mReceiver; mReceiver = null; Application application = Model.getApplication(); if (receiver != null && application != null) { try { application.unregisterReceiver(receiver); } catch (Exception e) { e.printStackTrace(); } } Model.dispose(); super.onDestroy(); if (application != null) MissService.start(application); } @Override public IBinder onBind(Intent intent) { return mBinder; } private void addAlarm(Context context) { Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.HOUR_OF_DAY, 0); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); calendar.add(Calendar.DATE, 1); final long startTime = calendar.getTimeInMillis(); // Service intent Intent intent = new Intent(context, MissAlarmService.class); PendingIntent sender = PendingIntent.getService(context, 0, intent, 0); // Schedule the alarm AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); am.cancel(sender); am.setRepeating(AlarmManager.RTC, startTime, INTERVAL, sender); } public class MissServiceBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action.equals(ACTION_MISS_WIDGET_REFRESH)) { mBinder.refreshWidget(); } } } class MissServiceImpl extends IMissServiceInterface.Stub implements SyncCallback { private final Context mContext; private final MissServiceBean mBean; private int mLeadDay; public MissServiceImpl(Context context) { mContext = context; mBean = new MissServiceBean(); mLeadDay = new SettingModel().getLeadTime(); orderAsync(); } @Override public void order() { try { clear(); updateSTTTCache(); updateNewestCache(); updateTimeLine(); updateContacts(); } catch (Exception e) { e.printStackTrace(); } } @Override public void orderAsync() { Runnable runnable = new Runnable() { @Override public void run() { order(); sendUpdateMainBroadcast(); } }; Model.getThreadPool().execute(runnable); } @Override public void destroy() { stopSelf(); } @Override public MissServiceBean getMissBean() { Model.log("MissService getMissBean", mBean.toString()); return mBean; } @Override public void add(long id) { RecordModel model = RecordModel.get(id); if (model == null) { Model.log("MissService add", "null"); return; } Model.log("MissService add", model.toString()); // Count mBean.add(model.getType()); // Newest NewestModel cache = new NewestModel(model); mBean.getNewest().addFirst(cache); // TimeLine RecordViewModel data = new RecordViewModel(); data.set(model); List<RecordViewModel> models = mBean.getTimeLine(); models.add(data); Collections.sort(models); sendUpdateMainBroadcast(); } @Override public void edit(long id) { RecordModel model = RecordModel.get(id); if (model == null) return; updateSTTTCache(); updateNewestCache(); editTimeLine(model); sendUpdateMainBroadcast(); } @Override public void delete(String mark, int type) { mBean.delete(type); deleteTimeLine(UUID.fromString(mark)); updateNewestCache(); sendUpdateMainBroadcast(); } @Override public void addContact(long id) throws RemoteException { ContactModel model = ContactModel.get(id); if (model == null) return; // TimeLine ContactViewModel data = new ContactViewModel(); data.set(model); List<ContactViewModel> models = mBean.getContacts(); models.add(data); Collections.sort(models); sendUpdateMainBroadcast(); } @Override public void editContact(long id) throws RemoteException { ContactModel model = ContactModel.get(id); if (model == null) return; List<ContactViewModel> models = mBean.getContacts(); UUID mark = model.getMark(); for (ContactViewModel d : models) { if (mark.equals(d.getId())) { d.set(model); Collections.sort(models); // Send notify sendUpdateMainBroadcast(); break; } } } @Override public void deleteContact(String mark) throws RemoteException { UUID id = UUID.fromString(mark); List<ContactViewModel> models = mBean.getContacts(); for (ContactViewModel d : models) { if (id.equals(d.getId())) { models.remove(d); // Send notify sendUpdateMainBroadcast(); break; } } } @Override public void sync() { try { Sync.sync(this); } catch (Exception e) { e.printStackTrace(); } } @Override public void refreshDesktop(int size) { mLeadDay = size; sendUpdateWidget(); } @Override public void syncStop(@StringRes int status) { // Update updateSTTTCache(); updateNewestCache(); // Broadcast Intent intent = new Intent(ACTION_MISS_SYNC); intent.putExtra(ACTION_MISS_SYNC_VALUE_STATUS, status); mContext.sendBroadcast(intent); sendUpdateMainBroadcast(); } @Override public void syncUpdate(SyncChangeModel syncModel) { // Sync Contacts List<ContactViewModel> addContacts = new ArrayList<ContactViewModel>(); List<ContactViewModel> contactViewModels = mBean.getContacts(); List<UUID> ids = syncModel.getContactAdd(); if (ids != null && ids.size() > 0) { for (UUID id : ids) { ContactModel model = ContactModel.get(id); ContactViewModel data = getListAdapterDataFromContactCache(id, contactViewModels); if (data == null) { if (model != null) { data = new ContactViewModel(); data.set(model); addContacts.add(data); } } else { if (model != null) { data.set(model); } } } } ids = syncModel.getContactEdit(); if (ids != null && ids.size() > 0) { for (UUID id : ids) { ContactModel model = ContactModel.get(id); ContactViewModel data = getListAdapterDataFromContactCache(id, contactViewModels); if (data == null) { if (model != null) { data = new ContactViewModel(); data.set(model); addContacts.add(data); } } else { if (model != null) { data.set(model); } } } } contactViewModels.addAll(addContacts); Collections.sort(contactViewModels); // Sync Records List<RecordViewModel> addRecords = new ArrayList<RecordViewModel>(); List<RecordViewModel> deleteRecords = new ArrayList<RecordViewModel>(); List<RecordViewModel> recordViewModels = mBean.getTimeLine(); ids = syncModel.getRecordAdd(); if (ids != null && ids.size() > 0) { for (UUID id : ids) { RecordModel model = RecordModel.get(id); RecordViewModel data = getListAdapterDataFromRecordCache(id, recordViewModels); if (data == null) { if (model != null) { data = new RecordViewModel(); data.set(model); addRecords.add(data); } } else { if (model != null) { data.set(model); } } } } ids = syncModel.getRecordEdit(); if (ids != null && ids.size() > 0) { for (UUID id : ids) { RecordModel model = RecordModel.get(id); RecordViewModel data = getListAdapterDataFromRecordCache(id, recordViewModels); if (data == null) { if (model != null) { data = new RecordViewModel(); data.set(model); addRecords.add(data); } } else { if (model != null) { data.set(model); } } } } ids = syncModel.getRecordDelete(); if (ids != null && ids.size() > 0) { for (UUID id : ids) { RecordViewModel data = getListAdapterDataFromRecordCache(id, recordViewModels); if (data != null) { deleteRecords.add(data); } } } recordViewModels.removeAll(deleteRecords); recordViewModels.addAll(addRecords); Collections.sort(recordViewModels); } private void clear() { mBean.getNewest().clear(); mBean.getTimeLine().clear(); mBean.setMemorialCount(0); mBean.setFutureCount(0); mBean.setBirthdayCount(0); } private RecordViewModel getListAdapterDataFromRecordCache(UUID id, List<RecordViewModel> models) { for (RecordViewModel d : models) { if (d.getId().equals(id)) return d; } return null; } private ContactViewModel getListAdapterDataFromContactCache(UUID id, List<ContactViewModel> models) { for (ContactViewModel d : models) { if (d.getId().equals(id)) return d; } return null; } private void updateSTTTCache() { mBean.setBirthdayCount(RecordModel.getCount(RecordModel.TYPE_BIRTHDAY)); mBean.setFutureCount(RecordModel.getCount(RecordModel.TYPE_FUTURE)); mBean.setMemorialCount(RecordModel.getCount(RecordModel.TYPE_MEMORIAL)); Model.log("MissService updateSTTTCache", mBean.toString()); } private void updateNewestCache() { List<NewestModel> models = mBean.getNewest(); models.clear(); List<RecordModel> recordModels = RecordModel.getNewest(5); for (RecordModel model : recordModels) { NewestModel cache = new NewestModel(model); models.add(cache); } } private void updateTimeLine() { List<RecordViewModel> dataList = new ArrayList<RecordViewModel>(); List<RecordModel> models = RecordModel.getAll(); if (models.size() > 512) models = models.subList(0, 512); for (RecordModel model : models) { RecordViewModel data = new RecordViewModel(); data.set(model); dataList.add(data); } List<RecordViewModel> recordViewModels = mBean.getTimeLine(); recordViewModels.clear(); recordViewModels.addAll(dataList); Collections.sort(recordViewModels); } private void updateContacts() { List<ContactViewModel> dataList = new ArrayList<ContactViewModel>(); List<ContactModel> models = ContactModel.getAll(); for (ContactModel model : models) { ContactViewModel data = new ContactViewModel(); data.set(model); dataList.add(data); } List<ContactViewModel> contactViewModels = mBean.getContacts(); contactViewModels.clear(); contactViewModels.addAll(dataList); Collections.sort(contactViewModels); } private void editTimeLine(RecordModel model) { List<RecordViewModel> models = mBean.getTimeLine(); UUID id = model.getMark(); for (RecordViewModel d : models) { if (id.equals(d.getId())) { d.set(model); Collections.sort(models); break; } } } private void deleteTimeLine(UUID id) { List<RecordViewModel> models = mBean.getTimeLine(); for (RecordViewModel d : models) { if (id.equals(d.getId())) { models.remove(d); break; } } } private String mWidgetValues = null; private String getBroadcastValue() { List<MissWidgetListData> dataList = new ArrayList<MissWidgetListData>(); List<RecordViewModel> models = mBean.getTimeLine(); if (models.size() > 0) { for (RecordViewModel model : models) { int day = model.getDayNow(); if ((day >= 0 && day <= mLeadDay) || dataList.size() < DAY_COUNT) { MissWidgetListData widget = new MissWidgetListData(model); dataList.add(widget); } else { break; } } } if (dataList.size() > 0) mWidgetValues = new Gson().toJson(dataList); else mWidgetValues = null; return mWidgetValues; } private void sendUpdateMainBroadcast() { Intent intent = new Intent(ACTION_MISS_MAIN); mContext.sendBroadcast(intent); // Update widget sendUpdateWidget(); } private void sendUpdateWidget() { Runnable runnable = new Runnable() { @Override public void run() { String values = getBroadcastValue(); sendUpdateWidgetBroadcast(values); } }; Model.getThreadPool().execute(runnable); } private void sendUpdateWidgetBroadcast(String values) { if (values == null) return; Bundle bundle = new Bundle(); bundle.putString(ACTION_MISS_WIDGET_VALUES, values); Intent intent = new Intent(ACTION_MISS_WIDGET); intent.putExtras(bundle); mContext.sendBroadcast(intent); } public void refreshWidget() { String values = mWidgetValues; sendUpdateWidgetBroadcast(values); } } }