package com.jasonchen.microlang.services; import android.annotation.SuppressLint; import android.app.Notification; 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.graphics.Bitmap; import android.os.Handler; import android.os.IBinder; import android.os.Vibrator; import android.text.TextUtils; import com.jasonchen.microlang.R; import com.jasonchen.microlang.activitys.WriteWeiboActivity; import com.jasonchen.microlang.beans.AccountBean; import com.jasonchen.microlang.beans.GeoBean; import com.jasonchen.microlang.beans.StatusDraftBean; import com.jasonchen.microlang.dao.StatusNewMsgDao; import com.jasonchen.microlang.database.DraftDBManager; import com.jasonchen.microlang.exception.WeiboException; import com.jasonchen.microlang.tasks.MyAsyncTask; import com.jasonchen.microlang.utils.NotificationUtility; import com.jasonchen.microlang.utils.SettingUtility; import com.jasonchen.microlang.utils.Utility; import com.jasonchen.microlang.utils.file.FileUploaderHttpHelper; import com.jasonchen.microlang.utils.image.ImageUtility; import java.io.File; import java.util.HashMap; import java.util.Map; import java.util.Random; import java.util.Set; /** * jasonchen * 2015/04/10 */ public class SendWeiboService extends Service { private Map<WeiboSendTask, Boolean> tasksResult = new HashMap<WeiboSendTask, Boolean>(); private Map<WeiboSendTask, Integer> tasksNotifications = new HashMap<WeiboSendTask, Integer>(); private Handler handler = new Handler(); private Vibrator vibrator; @Override public IBinder onBind(Intent intent) { return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { int lastNotificationId = intent.getIntExtra("lastNotificationId", -1); String token = intent.getStringExtra("token"); AccountBean account = (AccountBean) intent.getParcelableExtra("account"); String picPath = intent.getStringExtra("picPath"); String content = intent.getStringExtra("content"); GeoBean geoBean = (GeoBean) intent.getParcelableExtra("geo"); int visible = intent.getIntExtra("visible", 0); StatusDraftBean statusDraftBean = (StatusDraftBean) intent.getParcelableExtra("draft"); WeiboSendTask task = new WeiboSendTask(lastNotificationId, token, account, picPath, content, visible, geoBean, statusDraftBean); task.executeOnExecutor(MyAsyncTask.THREAD_POOL_EXECUTOR); tasksResult.put(task, false); vibrator = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE); return START_REDELIVER_INTENT; } public void stopServiceIfTasksAreEnd(WeiboSendTask currentTask) { tasksResult.put(currentTask, true); boolean isAllTaskEnd = true; Set<WeiboSendTask> taskSet = tasksResult.keySet(); for (WeiboSendTask task : taskSet) { if (!tasksResult.get(task)) { isAllTaskEnd = false; break; } } if (isAllTaskEnd) { vibrator.cancel(); stopForeground(true); stopSelf(); } } @SuppressLint("NewApi") private class WeiboSendTask extends MyAsyncTask<Void, Long, Void> { Notification notification; WeiboException e; long size; BroadcastReceiver receiver; PendingIntent pendingIntent; int lastNotificationId; String token; AccountBean account; String picPath; String content; int visible; GeoBean geoBean; StatusDraftBean statusDraftBean; public WeiboSendTask(int lastNotificationId, String token, AccountBean account, String picPath, String content, int visible, GeoBean geoBean, StatusDraftBean statusDraftBean) { this.lastNotificationId = lastNotificationId; this.token = token; this.account = account; this.content = content; this.picPath = picPath; this.geoBean = geoBean; this.statusDraftBean = statusDraftBean; } @SuppressLint("NewApi") @Override protected void onPreExecute() { super.onPreExecute(); Notification.Builder builder = new Notification.Builder(SendWeiboService.this) .setTicker(getString(R.string.sending)) .setContentTitle(getString(R.string.sending)) .setContentText(content) .setOnlyAlertOnce(true) .setOngoing(true) .setSmallIcon(R.drawable.ic_status_sending); if (!TextUtils.isEmpty(picPath)) { builder.setProgress(0, 100, false); } else { builder.setProgress(0, 100, true); } int notificationId = (lastNotificationId != -1) ? lastNotificationId : new Random().nextInt(Integer.MAX_VALUE); if (Utility.isJB()) { receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { WeiboSendTask.this.cancel(true); } }; IntentFilter intentFilter = new IntentFilter( "com.jasonchen.microlang.SendWeiboService.stop." + String.valueOf( notificationId)); registerReceiver(receiver, intentFilter); Intent broadcastIntent = new Intent( "com.jasonchen.microlang.SendWeiboService.stop." + String.valueOf( notificationId)); pendingIntent = PendingIntent.getBroadcast(SendWeiboService.this, 1, broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT); builder.addAction(R.drawable.ic_status_send_fail, getString(R.string.cancel), pendingIntent); notification = builder.build(); } else { notification = builder.getNotification(); } NotificationUtility.show(notification, notificationId); tasksNotifications.put(WeiboSendTask.this, notificationId); } private boolean sendPic(String uploadPicPath) throws WeiboException { return new StatusNewMsgDao(token).setVisibility(visible).setPic(uploadPicPath).setGeoBean(geoBean).sendNewMsg( content, new FileUploaderHttpHelper.ProgressListener() { @Override public void transferred(long data) { publishProgress(data); } @Override public void waitServerResponse() { publishProgress(-1L); } @Override public void completed() { publishProgress(size); } }); } private boolean sendText() throws WeiboException { return new StatusNewMsgDao(token).setVisibility(visible).setGeoBean(geoBean).sendNewMsg(content, null); } @Override protected Void doInBackground(Void... params) { boolean result = false; try { if (!TextUtils.isEmpty(picPath)) { String uploadPicPath = ImageUtility.compressPic(SendWeiboService.this, picPath); size = new File(uploadPicPath).length(); result = sendPic(uploadPicPath); } else { result = sendText(); } } catch (WeiboException e) { this.e = e; cancel(true); } if (!result) { cancel(true); } return null; } private double lastStatus = -1d; private long lastMillis = -1L; @SuppressLint("NewApi") @Override protected void onProgressUpdate(Long... values) { if (values.length > 0) { long data = values[0]; if (data != -1) { double r = data / (double) size; if (Math.abs(r - lastStatus) < 0.01d) { return; } if (System.currentTimeMillis() - lastMillis < 200L) { return; } lastStatus = r; lastMillis = System.currentTimeMillis(); Notification.Builder builder = new Notification.Builder(SendWeiboService.this) .setTicker(getString(R.string.send_photo)) .setContentTitle(getString(R.string.background_sending)) .setNumber((int) (r * 100)) .setContentText(content) .setProgress((int) size, (int) data, false) .setOnlyAlertOnce(true) .setOngoing(true) .setSmallIcon(R.drawable.upload_white); if (Utility.isJB()) { builder.addAction(R.drawable.ic_status_send_fail, getString(R.string.cancel), pendingIntent); notification = builder.build(); } else { notification = builder.getNotification(); } } else { Notification.Builder builder = new Notification.Builder(SendWeiboService.this) .setTicker(getString(R.string.send_photo)) .setContentTitle(getString(R.string.wait_server_response)) .setContentText(content) .setNumber(100) .setProgress(100, 100, false) .setOnlyAlertOnce(true) .setOngoing(true) .setSmallIcon(R.drawable.ic_status_sending); notification = builder.getNotification(); } NotificationUtility.show(notification, tasksNotifications.get(WeiboSendTask.this)); } } @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); if (statusDraftBean != null) { DraftDBManager.getInstance().remove(statusDraftBean.getId()); } showSuccessfulNotification(WeiboSendTask.this); if (receiver != null) { unregisterReceiver(receiver); } } @Override protected void onCancelled(Void aVoid) { super.onCancelled(aVoid); showFailedNotification(WeiboSendTask.this); if (receiver != null) { unregisterReceiver(receiver); } } private void showFailedNotification(final WeiboSendTask task) { Notification.Builder builder = new Notification.Builder(SendWeiboService.this) .setTicker(getString(R.string.send_failed)) .setContentTitle(getString(R.string.send_faile_click_to_open)) .setContentText(content) .setOnlyAlertOnce(true) .setAutoCancel(true) .setSmallIcon(R.drawable.ic_status_send_fail) .setOngoing(false); Intent notifyIntent = WriteWeiboActivity.startBecauseSendFailed(SendWeiboService.this, account, content, picPath, geoBean, statusDraftBean, String.format(SendWeiboService.this.getString(R.string.failed_reason), e.getError())); PendingIntent pendingIntent = PendingIntent.getActivity(SendWeiboService.this, 0, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT); builder.setContentIntent(pendingIntent); Notification notification; if (Utility.isJB()) { if (TextUtils.isEmpty(picPath)) { Notification.BigTextStyle bigTextStyle = new Notification.BigTextStyle(builder); bigTextStyle.setBigContentTitle(getString(R.string.send_faile_click_to_open)); bigTextStyle.bigText(content); bigTextStyle.setSummaryText(account.getUsernick()); builder.setStyle(bigTextStyle); } else { Bitmap bitmap = ImageUtility.getNotificationSendFailedPic(picPath); if (bitmap != null) { Notification.BigPictureStyle bigPictureStyle = new Notification.BigPictureStyle(builder); bigPictureStyle.setBigContentTitle( getString(R.string.send_faile_click_to_open)); bigPictureStyle.bigPicture(bitmap); bigPictureStyle.setSummaryText(account.getUsernick()); builder.setStyle(bigPictureStyle); } else { Notification.BigTextStyle bigTextStyle = new Notification.BigTextStyle( builder); bigTextStyle.setBigContentTitle( getString(R.string.send_faile_click_to_open)); bigTextStyle.bigText(content); bigTextStyle.setSummaryText(account.getUsernick()); builder.setStyle(bigTextStyle); } } Intent intent = new Intent(SendWeiboService.this, SendWeiboService.class); intent.putExtra("token", token); intent.putExtra("picPath", picPath); intent.putExtra("account", account); intent.putExtra("content", content); intent.putExtra("geo", geoBean); intent.putExtra("visible", visible); intent.putExtra("draft", statusDraftBean); intent.putExtra("lastNotificationId", tasksNotifications.get(task)); PendingIntent retrySendIntent = PendingIntent.getService(SendWeiboService.this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); builder.addAction(R.drawable.ic_status_sending, getString(R.string.retry_send), retrySendIntent); notification = builder.build(); } else { notification = builder.getNotification(); } final int id = tasksNotifications.get(task); NotificationUtility.show(notification, id); handler.postDelayed(new Runnable() { @Override public void run() { stopServiceIfTasksAreEnd(task); } }, 3000); } private void showSuccessfulNotification(final WeiboSendTask task) { vibrator = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE); long [] pattern = {100,400}; if(SettingUtility.allowVibrate()) { vibrator.vibrate(pattern, -1); } Notification.Builder builder = new Notification.Builder(SendWeiboService.this) .setTicker(getString(R.string.send_successfully)) .setContentTitle(getString(R.string.send_successfully)) .setOnlyAlertOnce(true) .setAutoCancel(true) .setSmallIcon(R.drawable.ic_status_send_success) .setOngoing(false); Notification notification = builder.getNotification(); final int id = tasksNotifications.get(task); NotificationUtility.show(notification, id); handler.postDelayed(new Runnable() { @Override public void run() { NotificationUtility.cancel(id); stopServiceIfTasksAreEnd(task); } }, 3000); } } }