package org.aisen.weibo.sina.service.publisher; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Handler; import android.os.Message; import android.text.TextUtils; import org.aisen.android.common.context.GlobalContext; import org.aisen.android.common.utils.FileUtils; import org.aisen.android.common.utils.KeyGenerator; import org.aisen.android.common.utils.Logger; import org.aisen.android.component.orm.extra.Extra; import org.aisen.android.network.http.Params; import org.aisen.android.network.task.TaskException; import org.aisen.android.network.task.WorkTask; import org.aisen.weibo.sina.base.AppContext; import org.aisen.weibo.sina.base.MyApplication; import org.aisen.weibo.sina.receiver.TimingBroadcastReceiver; import org.aisen.weibo.sina.service.PublishService; import org.aisen.weibo.sina.sinasdk.SinaSDK; import org.aisen.weibo.sina.sinasdk.bean.UploadPictureBean; import org.aisen.weibo.sina.sinasdk.bean.UploadPictureResultBean; import org.aisen.weibo.sina.sinasdk.bean.WeiBoUser; import org.aisen.weibo.sina.sinasdk.core.SinaErrorMsgUtil; import org.aisen.weibo.sina.support.bean.AccountBean; import org.aisen.weibo.sina.support.bean.PublishBean; import org.aisen.weibo.sina.support.bean.PublishBean.PublishStatus; import org.aisen.weibo.sina.support.bean.PublishType; import org.aisen.weibo.sina.support.sqlit.PublishDB; import org.aisen.weibo.sina.support.sqlit.SinaDB; import org.aisen.weibo.sina.support.utils.AisenUtils; import org.aisen.weibo.sina.ui.fragment.account.AccountFragment; import org.aisen.weibo.sina.ui.fragment.comment.TimelineDetailPagerFragment; import java.io.File; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class PublishManager extends Handler implements PublishQueue.PublishQueueCallback { public static final int publishDelay = 1; public static final String ACTION_PUBLISH_CHANNGED = "org.aisen.weibo.ACTION_PUBLISH_SUCCESSED"; private Context context; private PublishQueue publishQueue; private PublishNotifier publishNotifier; private PublishTask publishTask; private AccountBean mAccount; private WeiBoUser loggedIn; public PublishManager(Context context, AccountBean accountBean) { this.context = context.getApplicationContext(); this.mAccount = accountBean; this.loggedIn = accountBean.getUser(); publishQueue = new PublishQueue(this); publishNotifier = new PublishNotifier(context); publishInit(); } public void stop() { if (publishTask != null && publishTask.getStatus() != WorkTask.Status.FINISHED) publishTask.cancel(true); removeMessages(publishDelay); if (!AppContext.isLoggedIn() || !AppContext.getAccount().getUser().getIdstr().equals(loggedIn.getIdstr())) PublishNotifier.cancelAll(); if (publishQueue.size() > 0) { new WorkTask<WeiBoUser, Void, Void>() { @Override public Void workInBackground(WeiBoUser... params) throws TaskException { PublishBean bean = null; Logger.d(AccountFragment.TAG, String.format("共有%d个发布任务未完成", publishQueue.size())); while((bean = publishQueue.poll()) != null) { Logger.d(AccountFragment.TAG, "停止发布一个任务,添加到草稿"); bean.setStatus(PublishStatus.draft); PublishDB.addPublish(bean, params[0]); } return null; } }.execute(loggedIn); } } public void cancelPublish() { removeMessages(publishDelay); PublishBean bean = publishQueue.poll(); if (bean != null) { bean.setStatus(PublishStatus.draft); PublishDB.addPublish(bean, loggedIn); publishNotifier.notifyPublishCancelled(bean); refreshDraftbox(); onPublish(publishQueue.peek()); } } public void onPublish(PublishBean bean) { if (bean == null) return; // 如果队列为空,放入首位等待发送,否则,添加到队列等待发布 if (publishQueue.isEmpty()) { publishQueue.add(bean); } PublishBean firstBean = publishQueue.peek(); if (firstBean != null && firstBean.getId().equals(bean.getId())) { // 定时发布 if (bean.getTiming() > 0) { Logger.d(TimingBroadcastReceiver.TAG, bean.getText() + "-定时发布"); // 从队列移除 publishQueue.poll(); // 更改状态为草稿 bean.setStatus(PublishStatus.draft); // 添加到DB PublishDB.addPublish(bean, loggedIn); // 刷新草稿 refreshDraftbox(); // 发送广播 publishNotifier.notifyTimingPublish(bean); // 发布下一个 onPublish(publishQueue.peek()); // 刷新定时 MyApplication.refreshPublishAlarm(); } // 立即发布 else if (bean.getDelay() <= 0) { Logger.d(TimingBroadcastReceiver.TAG, bean.getText() + "-立即发布"); publishTask = new PublishTask(bean); publishTask.executeOnSerialExecutor(); } // 延迟发布 else { Logger.d(TimingBroadcastReceiver.TAG, bean.getText() + "-延迟发布"); publishNotifier.notifyPrePublish(bean); Message msg = obtainMessage(publishDelay); msg.obj = bean; bean.setDelay(bean.getDelay() - 1000); sendMessageDelayed(msg, 1000); if (bean.getStatus() != PublishStatus.waiting) { bean.setStatus(PublishStatus.waiting); PublishDB.updatePublish(bean, loggedIn); } } } else { Logger.d(TimingBroadcastReceiver.TAG, bean.getText() + "-添加到队列等等发布"); publishQueue.add(bean); if (firstBean == null) onPublish(bean); if (bean.getStatus() != PublishStatus.waiting) { bean.setStatus(PublishStatus.waiting); PublishDB.updatePublish(bean, loggedIn); } } refreshDraftbox(); } /** * 将添加状态的消息都加入到队列当中 */ public void publishInit() { List<PublishBean> beans = PublishDB.getPublishOfAddStatus(loggedIn); for (PublishBean bean : beans) publishQueue.add(bean); onPublish(publishQueue.peek()); } public void delete(PublishBean bean) { Iterator<PublishBean> iterator = publishQueue.iterator(); while (iterator.hasNext()) { if (bean == iterator.next()) { iterator.remove(); // TODO 删除一个发布任务,存入草稿 PublishDB.deletePublish(bean, loggedIn); break; } } } @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case publishDelay: PublishBean bean = (PublishBean) msg.obj; onPublish(bean); break; } } @Override public void onPublishPoll(PublishBean bean) { // 任务失败不从DB删除 if (bean.getStatus() != PublishStatus.faild) PublishDB.deletePublish(bean, loggedIn); refreshDraftbox(); } @Override public void onPublishAdd(PublishBean bean) { if (bean.getStatus() != PublishStatus.create) bean.setStatus(PublishStatus.draft); bean.setErrorMsg(""); PublishDB.addPublish(bean, loggedIn); } @Override public void onPublishPeek(PublishBean bean) { bean.setStatus(PublishStatus.sending); PublishDB.updatePublish(bean, loggedIn); //更新界面 refreshDraftbox(); } private synchronized void publishFinished(PublishBean bean) { publishQueue.poll(); Logger.w("publishFinished" + publishQueue.size()); // 队列发送完毕了,且当前运行的页面不是发布页面,就停止服务 if (publishQueue.size() == 0) context.stopService(new Intent(context, PublishService.class)); else { postDelayed(new Runnable() { @Override public void run() { onPublish(publishQueue.peek()); } }, 2 * 1000); } } private void refreshDraftbox() { Intent intent = new Intent(); intent.setAction(ACTION_PUBLISH_CHANNGED); context.sendBroadcast(intent); } class PublishTask extends WorkTask<Void, Void, Object> { PublishBean bean; public PublishTask(PublishBean bean) { this.bean = bean; } @Override protected void onPrepare() { super.onPrepare(); if (bean != null) publishNotifier.notifyPublishing(bean); } @Override protected void onFailure(TaskException exception) { super.onFailure(exception); if (bean != null) { // 响应成功,就让他发成功 if (TaskException.TaskError.socketTimeout.toString().equalsIgnoreCase(exception.getCode())) { onSuccess(null); } else { publishNotifier.notifyPublishFaild(bean, exception.getMessage()); bean.setStatus(PublishStatus.faild); SinaErrorMsgUtil util = new SinaErrorMsgUtil(); if (util.checkCode(exception.getCode()) != null) bean.setErrorMsg(util.checkCode(exception.getCode())); else bean.setErrorMsg(exception.getMessage()); PublishDB.updatePublish(bean, loggedIn); refreshDraftbox(); } } } @Override protected void onFinished() { super.onFinished(); if (bean != null){ publishFinished(bean); refreshDraftbox(); } } @Override protected void onSuccess(Object result) { super.onSuccess(result); if (bean != null) { // 回复微博、评论和转发微博时,通知刷新界面 if (bean.getType() == PublishType.commentCreate) { GlobalContext.getInstance().sendBroadcast(new Intent(TimelineDetailPagerFragment.ACTION_REFRESH_CMT_CREATE)); } else if (bean.getType() == PublishType.commentReply) { GlobalContext.getInstance().sendBroadcast(new Intent(TimelineDetailPagerFragment.ACTION_REFRESH_CMT_REPLY)); } else if (bean.getType() == PublishType.statusRepost) { GlobalContext.getInstance().sendBroadcast(new Intent(TimelineDetailPagerFragment.ACTION_REFRESH_REPOST)); } publishNotifier.notifyPublishSuccess(bean); PublishDB.deletePublish(bean, loggedIn); } } @Override public Object workInBackground(Void... params) throws TaskException { if (bean == null) { publishInit(); } else { // 发布微博(带图片) if (bean.getType() == PublishType.status) { if (!bean.getParams().containsKey("status")) bean.getParams().addParameter("status", bean.getText()); // 意见反馈或者分享图片 if (bean.getParams().containsKey("url") && // sina有分享GIF图片后不再是GIF图片的BUG !bean.getParams().getParameter("url").toLowerCase().endsWith(".gif")) { String url = bean.getParams().getParameter("url"); if (url.indexOf("/bmiddle/") != -1 && url.indexOf("sina") != -1) { url = url.replace("/bmiddle/", "/large/"); bean.getParams().addParameter("url", url); } return SinaSDK.getInstance(AppContext.getAccount().getAccessToken()).statusesUploadUrlText(bean.getParams()); } // 带图片 else if (bean.getPics() != null && bean.getPics().length > 0) { String[] images = bean.getPics(); Object result = null; // 2015-06-29 在这里切入多图上传支持,暂时支持挨个挨个上传图片不并发 // 如果只有一个图片,就用Aisen, if (images.length == 1) { String path = images[0]; if (path.toString().startsWith("content://")) { Uri uri = Uri.parse(path); path = FileUtils.getPath(GlobalContext.getInstance(), uri); } else { path = path.toString().replace("file://", ""); } Logger.w("上传文件路径 = " + path); File file = new File(path); if (!file.exists()) throw new TaskException("图片不存在或已删除"); // 压缩文件 file = AisenUtils.getUploadFile(context, file); Logger.w("上传图片大小" + (file.length() / 1024) + "KB"); result = SinaSDK.getInstance(AppContext.getAccount().getAccessToken()).statusesUpload(bean.getParams(), file); } // 如果存在多个图片,就用Weico高级权限 else { List<String> picIdList = new ArrayList<>(); for (int i = 0; i < images.length; i++) { String path = images[i]; // 检查这个图片是否已经上传过了 String pathKey = KeyGenerator.generateMD5(path); UploadPictureBean uploadPictureBean = SinaDB.getDB().selectById(new Extra(loggedIn.getIdstr(), null), UploadPictureBean.class, pathKey); if (uploadPictureBean != null && !TextUtils.isEmpty(uploadPictureBean.getPic_id())) { Logger.w("这个图片已经上传过了, resultId = " + uploadPictureBean.getPic_id() + ", path = " + path); picIdList.add(uploadPictureBean.getPic_id()); } else { uploadPictureBean = new UploadPictureBean(); uploadPictureBean.setKey(pathKey); uploadPictureBean.setPath(path); if (path.toString().startsWith("content://")) { Uri uri = Uri.parse(path); path = FileUtils.getPath(GlobalContext.getInstance(), uri); } else { path = path.toString().replace("file://", ""); } Logger.w(String.format("上传第%d个文件, 路径 = %s", i + 1, path)); File file = new File(path); if (!file.exists()) throw new TaskException("图片不存在或已删除"); // 压缩文件 file = AisenUtils.getUploadFile(context, file); Logger.w("上传图片大小" + (file.length() / 1024) + "KB"); // 开始上传 UploadPictureResultBean resultBean = SinaSDK.getInstance(mAccount.getAdvancedToken()).uploadPicture(file); Logger.w("成功上传一张图片,pic_id = " + resultBean.getPic_id()); uploadPictureBean.setPic_id(resultBean.getPic_id()); picIdList.add(resultBean.getPic_id()); // 更新到数据库 SinaDB.getDB().insertOrReplace(new Extra(loggedIn.getIdstr(), null), uploadPictureBean); } } // 图片都上传完了,开始发布微博 String picIdStr = ""; for (String picId : picIdList) { picIdStr = picIdStr + picId + ","; } picIdStr = picIdStr.substring(0, picIdStr.length() - 1); bean.getParams().addParameter("pic_id", picIdStr); return SinaSDK.getInstance(mAccount.getAccessToken()).statusesUploadUrlText(bean.getParams()); } // file.delete(); return result; } // 纯文字 else { return SinaSDK.getInstance(AppContext.getAccount().getAccessToken()).statusesUpdate(bean.getParams()); } } // 回复微博(同时转发微博) else if (bean.getType() == PublishType.commentCreate) { if (!bean.getParams().containsKey("comment")) bean.getParams().addParameter("comment", bean.getText()); // 评论微博同时转发 if (bean.getExtras().containsKey("forward") && Boolean.parseBoolean(bean.getExtras().getParameter("forward"))) { Params repostParams = new Params(); repostParams.addParameter("id", bean.getParams().getParameter("id")); repostParams.addParameter("status", bean.getParams().getParameter("comment")); SinaSDK.getInstance(AppContext.getAccount().getAccessToken()).statusesReport(repostParams); } return SinaSDK.getInstance(AppContext.getAccount().getAccessToken()).commentCreate(bean.getParams()); } // 回复评论 else if (bean.getType() == PublishType.commentReply) { if (!bean.getParams().containsKey("comment")) bean.getParams().addParameter("comment", bean.getText()); // 评论微博同时转发 if (bean.getExtras().containsKey("forward") && Boolean.parseBoolean(bean.getExtras().getParameter("forward"))) { Params repostParams = new Params(); repostParams.addParameter("id", bean.getParams().getParameter("id")); repostParams.addParameter("status", bean.getParams().getParameter("comment")); SinaSDK.getInstance(AppContext.getAccount().getAccessToken()).statusesReport(repostParams); } return SinaSDK.getInstance(AppContext.getAccount().getAccessToken()).commentsReply(bean.getParams()); } // 转发微博 else if (bean.getType() == PublishType.statusRepost) { if (!bean.getParams().containsKey("status")) bean.getParams().addParameter("status", bean.getText()); return SinaSDK.getInstance(AppContext.getAccount().getAccessToken()).statusesReport(bean.getParams()); } } throw new TaskException("发送失败"); } } }