PageRenderTime 454ms CodeModel.GetById 40ms RepoModel.GetById 1ms app.codeStats 0ms

/dateLoveInternational/src/main/java/com/datelove/online/International/adapter/ChatAdapter.java

https://bitbucket.org/juzhiwiscom/datelove
Java | 1576 lines | 1147 code | 186 blank | 243 comment | 160 complexity | b4bcd0d643853514ff59bc9d29877400 MD5 | raw file
  1. package com.datelove.online.International.adapter;
  2. import android.app.Activity;
  3. import android.app.Dialog;
  4. import android.content.Context;
  5. import android.graphics.Bitmap;
  6. import android.graphics.BitmapFactory;
  7. import android.graphics.Color;
  8. import android.graphics.drawable.AnimationDrawable;
  9. import android.graphics.drawable.Drawable;
  10. import android.net.Uri;
  11. import android.os.AsyncTask;
  12. import android.os.Build;
  13. import android.renderscript.Allocation;
  14. import android.renderscript.Element;
  15. import android.renderscript.RenderScript;
  16. import android.renderscript.ScriptIntrinsicBlur;
  17. import android.support.v4.app.FragmentActivity;
  18. import android.support.v7.widget.LinearLayoutManager;
  19. import android.support.v7.widget.RecyclerView;
  20. import android.text.TextUtils;
  21. import android.view.View;
  22. import android.view.ViewGroup;
  23. import android.widget.ImageView;
  24. import android.widget.LinearLayout;
  25. import android.widget.RelativeLayout;
  26. import android.widget.TextView;
  27. import com.alibaba.fastjson.JSON;
  28. import com.datelove.online.International.R;
  29. import com.datelove.online.International.activity.BuyServiceActivity;
  30. import com.datelove.online.International.activity.PictureBrowseActivity;
  31. import com.datelove.online.International.activity.UserInfoDetailActivity;
  32. import com.datelove.online.International.bean.BaseModel;
  33. import com.datelove.online.International.bean.Image;
  34. import com.datelove.online.International.bean.Message;
  35. import com.datelove.online.International.bean.QaAnswer;
  36. import com.datelove.online.International.bean.QaQuestion;
  37. import com.datelove.online.International.bean.WriteMsg;
  38. import com.datelove.online.International.constant.IConfigConstant;
  39. import com.datelove.online.International.constant.IUrlConstant;
  40. import com.datelove.online.International.event.MessageChangedEvent;
  41. import com.datelove.online.International.event.RefreshChatEvent;
  42. import com.datelove.online.International.utils.FileUtil;
  43. import com.datelove.online.International.utils.GetBitmapUtils;
  44. import com.datelove.online.International.utils.RecordUtil;
  45. import com.datelove.online.International.utils.Utils;
  46. import com.datelove.online.International.xml.PlatformInfoXml;
  47. import com.datelove.online.International.xml.UserInfoXml;
  48. import com.library.adapter.recyclerview.MultiItemRecyclerViewAdapter;
  49. import com.library.adapter.recyclerview.RecyclerViewHolder;
  50. import com.library.dialog.OnDoubleDialogClickListener;
  51. import com.library.imageloader.CircleTransformation;
  52. import com.library.imageloader.ImageLoader;
  53. import com.library.imageloader.ImageLoaderUtil;
  54. import com.library.utils.DensityUtil;
  55. import com.library.utils.DialogUtil;
  56. import com.library.utils.TimeUtil;
  57. import com.library.utils.ToastUtil;
  58. import com.library.utils.Util;
  59. import com.library.widgets.ChatImageView;
  60. import com.wonderkiln.blurkit.BlurLayout;
  61. import com.zhy.http.okhttp.OkHttpUtils;
  62. import com.zhy.http.okhttp.callback.Callback;
  63. import org.greenrobot.eventbus.EventBus;
  64. import java.io.File;
  65. import java.io.IOException;
  66. import java.io.InputStream;
  67. import java.net.HttpURLConnection;
  68. import java.net.MalformedURLException;
  69. import java.net.URL;
  70. import java.util.ArrayList;
  71. import java.util.List;
  72. import okhttp3.Call;
  73. import okhttp3.Response;
  74. /**
  75. * 聊天信息适配器,多item布局
  76. * Created by zhangdroid on 2016/8/17.
  77. */
  78. public class ChatAdapter extends MultiItemRecyclerViewAdapter<Message> {
  79. // 消息类型常量
  80. /**
  81. * 管理员消息
  82. */
  83. private static final String MSG_TYPE_ADMIN = "3";
  84. /**
  85. * 文字消息
  86. */
  87. private static final String MSG_TYPE_TEXT = "4";
  88. /**
  89. * 语音消息
  90. */
  91. private static final String MSG_TYPE_VOICE = "7";
  92. /**
  93. * QA消息
  94. */
  95. private static final String MSG_TYPE_QA = "8";
  96. /**
  97. * 图片消息
  98. */
  99. private static final String MSG_TYPE_IMAGE = "10";
  100. // item type常量
  101. /**
  102. * 文字聊天(对方)
  103. */
  104. private static final int CHAT_TYPE_MSG_LEFT = -1;
  105. /**
  106. * 文字聊天(我方)
  107. */
  108. private static final int CHAT_TYPE_MSG_RIGHT = 1;
  109. /**
  110. * 语音聊天(对方)
  111. */
  112. private static final int CHAT_TYPE_VOICE_LEFT = -2;
  113. /**
  114. * 语音聊天(我方)
  115. */
  116. private static final int CHAT_TYPE_VOICE_RIGHT = 2;
  117. /**
  118. * QA聊天(对方)
  119. */
  120. private static final int CHAT_TYPE_QA_LEFT = -3;
  121. /**
  122. * 图片消息(对方)
  123. */
  124. private static final int CHAT_TYPE_IMAGE_LEFT = -4;
  125. /**
  126. * 图片消息(我方)
  127. */
  128. private static final int CHAT_TYPE_IMAGE_RIGHT = 4;
  129. // 语音播放动画
  130. private AnimationDrawable mVoiceAnimLeft;
  131. private AnimationDrawable mVoiceAnimRight;
  132. /**
  133. * 对方id
  134. */
  135. private String mUId;
  136. /**
  137. * 对方用户头像
  138. */
  139. private String mAvatarUrl;
  140. /**
  141. * 服务器时间戳毫秒数
  142. */
  143. private long mServerSystemTime;
  144. /**
  145. * 是否支付拦截
  146. */
  147. private boolean mIsIntercept;
  148. /**
  149. * 所有图片列表缓存,用来展示大图浏览
  150. */
  151. private List<Image> mAllImageList = new ArrayList<Image>();
  152. /**
  153. * 是否显示图片加载进度
  154. */
  155. private boolean mIsShowImgLoading;
  156. /**
  157. * 是否显示图片重发
  158. */
  159. private boolean mIsShowImgRetry;
  160. /**
  161. * 是否显示语音加载进度
  162. */
  163. private boolean mIsShowVoiceLoading;
  164. /**
  165. * 是否显示语音重发
  166. */
  167. private boolean mIsShowVoiceRetry;
  168. /**
  169. * 设置对方用户头像
  170. *
  171. * @param url
  172. */
  173. public void setAvatarUrl(String url) {
  174. this.mAvatarUrl = url;
  175. }
  176. public void setServerSystemTime(long serverSystemTime) {
  177. this.mServerSystemTime = serverSystemTime;
  178. }
  179. public void isIntercept(boolean isIntercept) {
  180. this.mIsIntercept = isIntercept;
  181. }
  182. public void setAllImageList(List<Image> allImageList) {
  183. this.mAllImageList = allImageList;
  184. }
  185. public void isShowImgLoading(boolean isShowImgLoading) {
  186. this.mIsShowImgLoading = isShowImgLoading;
  187. }
  188. public void isShowImgRetry(boolean isShowImgRetry) {
  189. this.mIsShowImgRetry = isShowImgRetry;
  190. }
  191. public void isShowVoiceLoading(boolean isShowVoiceLoading) {
  192. this.mIsShowVoiceLoading = isShowVoiceLoading;
  193. }
  194. public void isShowVoiceRetry(boolean isShowVoiceRetry) {
  195. this.mIsShowVoiceRetry = isShowVoiceRetry;
  196. }
  197. public ChatAdapter(Context context, int layoutResId) {
  198. this(context, layoutResId, null);
  199. }
  200. public ChatAdapter(Context context, int layoutResId, List<Message> list) {
  201. super(context, layoutResId, list);
  202. this.mContext = context;
  203. // 对方语音动画
  204. List<Drawable> lefList = new ArrayList<Drawable>();
  205. lefList.add(mContext.getResources().getDrawable(R.drawable.msg_voice_left_one));
  206. lefList.add(mContext.getResources().getDrawable(R.drawable.msg_voice_left_two));
  207. lefList.add(mContext.getResources().getDrawable(R.drawable.msg_voice_left_three));
  208. mVoiceAnimLeft = Utils.getFrameAnim(lefList, true, 300);
  209. // 我方语音动画
  210. List<Drawable> rightList = new ArrayList<Drawable>();
  211. rightList.add(mContext.getResources().getDrawable(R.drawable.msg_voice_right_one));
  212. rightList.add(mContext.getResources().getDrawable(R.drawable.msg_voice_right_two));
  213. rightList.add(mContext.getResources().getDrawable(R.drawable.msg_voice_right_three));
  214. mVoiceAnimRight = Utils.getFrameAnim(rightList, true, 300);
  215. }
  216. @Override
  217. protected int getItemViewType(int position, Message message) {
  218. System.out.println("5555555555555:::"+position);
  219. String userId = message.getUid();
  220. if (!TextUtils.isEmpty(userId)) {
  221. if (!userId.equals(UserInfoXml.getUID())) {
  222. mUId = userId;
  223. }
  224. String msgType = message.getMsgType();
  225. if (userId.equals(UserInfoXml.getUID())) {// 己方消息
  226. if (!TextUtils.isEmpty(msgType)) {
  227. if (MSG_TYPE_TEXT.equals(msgType)) {// 文本消息
  228. return CHAT_TYPE_MSG_RIGHT;
  229. } else if (MSG_TYPE_VOICE.equals(msgType)) {// 语音消息
  230. return CHAT_TYPE_VOICE_RIGHT;
  231. } else if (MSG_TYPE_IMAGE.equals(msgType)) {// 图片消息
  232. return CHAT_TYPE_IMAGE_RIGHT;
  233. }
  234. }
  235. } else { // 对方消息
  236. if (!TextUtils.isEmpty(msgType)) {
  237. if (MSG_TYPE_ADMIN.equals(msgType)) {// 管理员消息
  238. return CHAT_TYPE_MSG_LEFT;
  239. } else if (MSG_TYPE_TEXT.equals(msgType)) {// 文本消息
  240. return CHAT_TYPE_MSG_LEFT;
  241. } else if (MSG_TYPE_VOICE.equals(msgType)) {// 语音消息
  242. return CHAT_TYPE_VOICE_LEFT;
  243. } else if (MSG_TYPE_QA.equals(msgType)) {// QA消息
  244. return CHAT_TYPE_QA_LEFT;
  245. } else if (MSG_TYPE_IMAGE.equals(msgType)) {// 图片消息
  246. return CHAT_TYPE_IMAGE_LEFT;
  247. }
  248. }
  249. }
  250. }
  251. return 0;
  252. }
  253. @Override
  254. protected int getItemLayoutResId(int viewType) {
  255. int layoutResId = 0;
  256. switch (viewType) {
  257. case CHAT_TYPE_MSG_LEFT:// 对方文字消息
  258. layoutResId = R.layout.item_chat_msg_left;
  259. break;
  260. case CHAT_TYPE_MSG_RIGHT:// 我方文字消息
  261. layoutResId = R.layout.item_chat_msg_right;
  262. break;
  263. case CHAT_TYPE_VOICE_LEFT:// 对方语音消息
  264. layoutResId = R.layout.item_chat_voice_left;
  265. break;
  266. case CHAT_TYPE_VOICE_RIGHT:// 我方语音消息
  267. layoutResId = R.layout.item_chat_voice_right;
  268. break;
  269. case CHAT_TYPE_QA_LEFT:// 对方QA消息
  270. layoutResId = R.layout.item_chat_qa;
  271. break;
  272. case CHAT_TYPE_IMAGE_LEFT:// 对方图片消息
  273. layoutResId = R.layout.item_chat_image_left;
  274. break;
  275. case CHAT_TYPE_IMAGE_RIGHT:// 我方图片消息
  276. layoutResId = R.layout.item_chat_image_right;
  277. break;
  278. }
  279. return layoutResId;
  280. }
  281. @Override
  282. protected void convert(int position, RecyclerViewHolder viewHolder, Message bean) {
  283. if (bean != null) {
  284. String userId = bean.getUid();
  285. if (!TextUtils.isEmpty(userId)) {
  286. String msgType = bean.getMsgType();
  287. if (userId.equals(UserInfoXml.getUID())) {// 己方消息
  288. if (!TextUtils.isEmpty(msgType)) {
  289. switch (msgType) {
  290. case MSG_TYPE_TEXT:// 文本消息
  291. setRightMsg(viewHolder, bean);
  292. break;
  293. case MSG_TYPE_VOICE:// 语音消息
  294. setRightVoiceMsg(viewHolder, bean);
  295. break;
  296. case MSG_TYPE_IMAGE://图片消息
  297. setRightImageMsg(viewHolder, bean);
  298. break;
  299. }
  300. }
  301. } else { // 对方消息
  302. if (!TextUtils.isEmpty(msgType)) {
  303. if (!TextUtils.isEmpty(msgType)) {
  304. switch (msgType) {
  305. case MSG_TYPE_ADMIN:// 管理员消息
  306. setLeftMsg(viewHolder, bean, true);
  307. break;
  308. case MSG_TYPE_TEXT:// 文本消息
  309. setLeftMsg(viewHolder, bean, false);
  310. break;
  311. case MSG_TYPE_VOICE:// 语音消息
  312. setLeftVoiceMsg(viewHolder, bean);
  313. break;
  314. case MSG_TYPE_QA:// QA消息
  315. setQaMesssage(viewHolder, bean);
  316. break;
  317. case MSG_TYPE_IMAGE://图片消息
  318. returnBitmap(bean.getChatImage().getThumbnailUrlM(), viewHolder, bean);
  319. break;
  320. }
  321. }
  322. }
  323. }
  324. }
  325. }
  326. }
  327. /**
  328. * 设置对方文本消息
  329. *
  330. * @param viewHolder
  331. * @param message {Message}对象
  332. * @param isAdmin 是否为管理员消息
  333. */
  334. private void setLeftMsg(RecyclerViewHolder viewHolder, final Message message, boolean isAdmin) {
  335. if (message != null) {
  336. // final BlurLayout blurLayout = (BlurLayout) viewHolder.getView(R.id.blurLayout);
  337. // 消息发送时间
  338. viewHolder.setText(R.id.chat_qa_msg_time_left, TimeUtil.getLocalTime(mContext, mServerSystemTime, message.getCreateDateMills()));
  339. // 头像
  340. ImageView ivAvatar = (ImageView) viewHolder.getView(R.id.chat_qa_msg_avatar_left);
  341. if (isAdmin) {
  342. } else {
  343. ImageLoaderUtil.getInstance().loadImage(mContext, new ImageLoader.Builder()
  344. .url(mAvatarUrl).transform(new CircleTransformation()).imageView(ivAvatar).build());
  345. // 点击头像可查看用户详情
  346. ivAvatar.setOnClickListener(new View.OnClickListener() {
  347. @Override
  348. public void onClick(View v) {
  349. UserInfoDetailActivity.toUserInfoDetailActivity((Activity) mContext, message.getUid(), null, UserInfoDetailActivity.SOURCE_FROM_CHAT_CONTENT);
  350. }
  351. });
  352. }
  353. // 聊天内容
  354. String content = message.getContent();
  355. if (!TextUtils.isEmpty(content)) {
  356. final TextView textview = (TextView) viewHolder.getView(R.id.chat_qa_msg_question);
  357. textview.setText(content);
  358. textview.post(new Runnable(){
  359. public void run() {
  360. //这里获取宽高
  361. int width = textview.getWidth();
  362. int height = textview.getHeight();
  363. // blurLayout.setMinimumWidth(width);
  364. // blurLayout.setMinimumHeight(height);
  365. }
  366. });
  367. // textview.buildDrawingCache();
  368. // Bitmap bmp = textview.getDrawingCache();
  369. // FastBlur.blur(bmp, textview, hover_view, context);
  370. }
  371. }
  372. }
  373. /**
  374. * 设置己方文本消息
  375. *
  376. * @param viewHolder
  377. * @param message
  378. */
  379. private void setRightMsg(RecyclerViewHolder viewHolder, final Message message) {
  380. if (message != null) {
  381. // 消息发送时间
  382. viewHolder.setText(R.id.chat_msg_time_right, TimeUtil.getLocalTime(mContext, mServerSystemTime, message.getCreateDateMills()));
  383. // 头像
  384. ImageView ivAvatar = (ImageView) viewHolder.getView(R.id.chat_qa_msg_avatar_Right);
  385. ImageLoaderUtil.getInstance().loadImage(mContext, new ImageLoader.Builder()
  386. .url(UserInfoXml.getAvatarUrl()).transform(new CircleTransformation()).imageView(ivAvatar).build());
  387. // 点击头像可查看用户详情
  388. ivAvatar.setOnClickListener(new View.OnClickListener() {
  389. @Override
  390. public void onClick(View v) {
  391. UserInfoDetailActivity.toUserInfoDetailActivity((Activity) mContext, message.getUid(), null, UserInfoDetailActivity.SOURCE_FROM_CHAT_CONTENT);
  392. }
  393. });
  394. // 聊天内容
  395. String content = message.getContent();
  396. if (!TextUtils.isEmpty(content)) {
  397. viewHolder.setText(R.id.chat_msg_right, content);
  398. }
  399. }
  400. }
  401. /**
  402. * 设置对方语音消息
  403. *
  404. * @param viewHolder
  405. * @param message
  406. */
  407. private void setLeftVoiceMsg(final RecyclerViewHolder viewHolder, final Message message) {
  408. if (message != null) {
  409. // 消息发送时间
  410. viewHolder.setText(R.id.chat_voice_lasttime_left, TimeUtil.getLocalTime(mContext, mServerSystemTime, message.getCreateDateMills()));
  411. // 头像
  412. ImageView ivAvatar = (ImageView) viewHolder.getView(R.id.chat_voice_avatar_left);
  413. ImageLoaderUtil.getInstance().loadImage(mContext, new ImageLoader.Builder()
  414. .url(mAvatarUrl).transform(new CircleTransformation()).imageView(ivAvatar).build());
  415. // 点击头像可查看用户详情
  416. ivAvatar.setOnClickListener(new View.OnClickListener() {
  417. @Override
  418. public void onClick(View v) {
  419. UserInfoDetailActivity.toUserInfoDetailActivity((Activity) mContext, message.getUid(), "0", UserInfoDetailActivity.SOURCE_FROM_CHAT_CONTENT);
  420. }
  421. });
  422. // 将语音下载到本地(根据用户id存放到不同的目录下)
  423. String downloadFileDir = FileUtil.RECORD_DIRECTORY_PATH + File.separator + message.getUid();
  424. String downloadFileName = FileUtil.createFileNameByDate(message.getCreateDate()) + ".mp3";
  425. final String downloadPath = downloadFileDir + File.separator + downloadFileName;
  426. FileUtil.downloadFile(message.getAudioUrl(), downloadFileDir, downloadFileName);
  427. // 设置语音信息
  428. String audioTime = message.getAudioTime();
  429. if (!TextUtils.isEmpty(audioTime)) {
  430. viewHolder.setText(R.id.chat_voice_left_tv, audioTime + "''");
  431. }
  432. final ImageView ivUnread = (ImageView) viewHolder.getView(R.id.chat_voice_left_unread);
  433. String readState = message.getRecevStatus();
  434. if (!TextUtils.isEmpty(readState) && "0".equals(readState)) {
  435. ivUnread.setVisibility(View.VISIBLE);
  436. } else {
  437. ivUnread.setVisibility(View.GONE);
  438. }
  439. // 点击播放语音
  440. final ImageView ivAnim = (ImageView) viewHolder.getView(R.id.chat_voice_left_iv);
  441. ivAnim.setImageResource(R.drawable.msg_voice_left_three);
  442. viewHolder.getView(R.id.chat_voice_left).setOnClickListener(new View.OnClickListener() {
  443. @Override
  444. public void onClick(View v) {
  445. // 更新状态为已读
  446. String readState = message.getRecevStatus();
  447. if (!TextUtils.isEmpty(readState) && "0".equals(readState)) {
  448. message.setRecevStatus("1");
  449. ivUnread.setVisibility(View.GONE);
  450. updateVoiceMsgStatus(message.getId());
  451. }
  452. // 当前是否正在播放语音
  453. if (RecordUtil.getInstance().isPlaying()) {
  454. // 先停止正在播放的语音
  455. RecordUtil.getInstance().stop();
  456. if (mVoiceAnimLeft.isRunning()) {
  457. mVoiceAnimLeft.stop();
  458. }
  459. if (mVoiceAnimRight.isRunning()) {
  460. mVoiceAnimRight.stop();
  461. }
  462. }
  463. File file = new File(downloadPath);
  464. if (file.exists()) {
  465. // 播放/停止语音动画
  466. if (!mVoiceAnimLeft.isRunning()) {
  467. ivAnim.setImageDrawable(mVoiceAnimLeft);
  468. mVoiceAnimLeft.start();
  469. }
  470. // 播放/暂停语音
  471. RecordUtil.getInstance().toggle(downloadPath, new RecordUtil.OnPlayerListener() {
  472. @Override
  473. public void onCompleted() {
  474. if (mVoiceAnimLeft.isRunning()) {
  475. mVoiceAnimLeft.stop();
  476. ivAnim.setImageResource(R.drawable.msg_voice_left_three);
  477. }
  478. }
  479. @Override
  480. public void onPaused() {
  481. if (mVoiceAnimLeft.isRunning()) {
  482. mVoiceAnimLeft.stop();
  483. ivAnim.setImageResource(R.drawable.msg_voice_left_three);
  484. }
  485. }
  486. });
  487. } else {
  488. ToastUtil.showShortToast(mContext, mContext.getResources().getString(R.string.not_exist));
  489. }
  490. }
  491. });
  492. }
  493. }
  494. /**
  495. * 设置我方语音消息
  496. *
  497. * @param viewHolder
  498. * @param message
  499. */
  500. private void setRightVoiceMsg(RecyclerViewHolder viewHolder, final Message message) {
  501. if (message != null) {
  502. // 消息发送时间
  503. viewHolder.setText(R.id.chat_voice_lasttime_right, TimeUtil.getLocalTime(mContext, mServerSystemTime, message.getCreateDateMills()));
  504. // 头像
  505. ImageView ivAvatar = (ImageView) viewHolder.getView(R.id.chat_voice_avatar_right);
  506. ImageLoaderUtil.getInstance().loadImage(mContext, new ImageLoader.Builder()
  507. .url(UserInfoXml.getAvatarUrl()).transform(new CircleTransformation()).imageView(ivAvatar).build());
  508. // 点击头像可查看用户详情
  509. ivAvatar.setOnClickListener(new View.OnClickListener() {
  510. @Override
  511. public void onClick(View v) {
  512. UserInfoDetailActivity.toUserInfoDetailActivity((Activity) mContext, message.getUid(), "0", UserInfoDetailActivity.SOURCE_FROM_CHAT_CONTENT);
  513. }
  514. });
  515. // 设置语音信息
  516. String audioTime = message.getAudioTime();
  517. if (!TextUtils.isEmpty(audioTime)) {
  518. viewHolder.setText(R.id.chat_voice_right_tv, audioTime + "''");
  519. }
  520. String tempPath;
  521. String audioUrl = message.getAudioUrl();
  522. if (Utils.isHttpUrl(audioUrl)) {
  523. // 将语音下载到本地(根据用户id存放到不同的目录下)
  524. String downloadFileDir = FileUtil.RECORD_DIRECTORY_PATH + File.separator + message.getUid();
  525. String downloadFileName = FileUtil.createFileNameByDate(message.getCreateDate()) + ".mp3";
  526. tempPath = downloadFileDir + File.separator + downloadFileName;
  527. FileUtil.downloadFile(audioUrl, downloadFileDir, downloadFileName);
  528. } else {
  529. tempPath = audioUrl;
  530. }
  531. final String localPath = tempPath;
  532. // 语音加载进度
  533. final ImageView ivLoading = (ImageView) viewHolder.getView(R.id.chat_voice_msg_loading);
  534. AnimationDrawable animationDrawable = Util.getFrameAnim(Utils.getLoadingDrawableList(mContext), true, 50);
  535. animationDrawable.start();
  536. ivLoading.setImageDrawable(animationDrawable);
  537. ivLoading.setVisibility(mIsShowVoiceLoading ? View.VISIBLE : View.GONE);
  538. // 图片重发
  539. final ImageView ivRetry = (ImageView) viewHolder.getView(R.id.chat_voice_msg_retry);
  540. ivRetry.setVisibility(mIsShowVoiceRetry ? View.VISIBLE : View.GONE);
  541. ivRetry.setOnClickListener(new View.OnClickListener() {
  542. @Override
  543. public void onClick(View v) {
  544. // 点击重发
  545. DialogUtil.showDoubleBtnDialog(((FragmentActivity) mContext).getSupportFragmentManager(),
  546. null, mContext.getString(R.string.retry_message), mContext.getString(R.string.positive),
  547. mContext.getString(R.string.negative), true, new OnDoubleDialogClickListener() {
  548. @Override
  549. public void onPositiveClick(View view) {
  550. mIsShowVoiceLoading = true;
  551. mIsShowVoiceRetry = false;
  552. ivLoading.setVisibility(View.VISIBLE);
  553. ivRetry.setVisibility(View.GONE);
  554. sendVoiceMsg(new File(localPath), message);
  555. }
  556. @Override
  557. public void onNegativeClick(View view) {
  558. }
  559. });
  560. }
  561. });
  562. // 点击播放语音
  563. final ImageView ivAnim = (ImageView) viewHolder.getView(R.id.chat_voice_right_iv);
  564. ivAnim.setImageResource(R.drawable.msg_voice_right_three);
  565. viewHolder.getView(R.id.chat_voice_right).setOnClickListener(new View.OnClickListener() {
  566. @Override
  567. public void onClick(View v) {
  568. // 当前是否正在播放语音
  569. if (RecordUtil.getInstance().isPlaying()) {
  570. // 先停止正在播放的语音
  571. RecordUtil.getInstance().stop();
  572. if (mVoiceAnimLeft.isRunning()) {
  573. mVoiceAnimLeft.stop();
  574. }
  575. if (mVoiceAnimRight.isRunning()) {
  576. mVoiceAnimRight.stop();
  577. }
  578. }
  579. File file = new File(localPath);
  580. if (file.exists()) {
  581. // 播放/停止语音动画
  582. if (!mVoiceAnimRight.isRunning()) {
  583. ivAnim.setImageDrawable(mVoiceAnimRight);
  584. mVoiceAnimRight.start();
  585. }
  586. // 播放/暂停语音
  587. RecordUtil.getInstance().toggle(localPath, new RecordUtil.OnPlayerListener() {
  588. @Override
  589. public void onCompleted() {
  590. if (mVoiceAnimRight.isRunning()) {
  591. mVoiceAnimRight.stop();
  592. ivAnim.setImageResource(R.drawable.msg_voice_right_three);
  593. }
  594. }
  595. @Override
  596. public void onPaused() {
  597. if (mVoiceAnimRight.isRunning()) {
  598. mVoiceAnimRight.stop();
  599. ivAnim.setImageResource(R.drawable.msg_voice_right_three);
  600. }
  601. }
  602. });
  603. } else {
  604. ToastUtil.showShortToast(mContext, mContext.getResources().getString(R.string.not_exist));
  605. }
  606. }
  607. });
  608. }
  609. }
  610. /**
  611. * 设置对方QA消息
  612. *
  613. * @param viewHolder
  614. * @param message
  615. */
  616. private void setQaMesssage(RecyclerViewHolder viewHolder, final Message message) {
  617. if (message != null) {
  618. // 消息发送时间
  619. viewHolder.setText(R.id.chat_qa_msg_time_left, TimeUtil.getLocalTime(mContext, mServerSystemTime, message.getCreateDateMills()));
  620. // 头像
  621. ImageView ivAvatar = (ImageView) viewHolder.getView(R.id.chat_qa_msg_avatar_left);
  622. ImageLoaderUtil.getInstance().loadImage(mContext, new ImageLoader.Builder()
  623. .url(mAvatarUrl).transform(new CircleTransformation()).imageView(ivAvatar).build());
  624. // 点击头像可查看用户详情
  625. ivAvatar.setOnClickListener(new View.OnClickListener() {
  626. @Override
  627. public void onClick(View v) {
  628. UserInfoDetailActivity.toUserInfoDetailActivity((Activity) mContext, message.getUid(), null, UserInfoDetailActivity.SOURCE_FROM_CHAT_CONTENT);
  629. }
  630. });
  631. // QA问题
  632. String content = message.getContent();
  633. if (!TextUtils.isEmpty(content)) {
  634. viewHolder.setText(R.id.chat_qa_msg_question, content);
  635. }
  636. // QA答案列表
  637. QaQuestion qaQuestion = message.getQaQuestion();
  638. if (qaQuestion != null) {
  639. List<QaAnswer> qaAnswerList = qaQuestion.getListQaAnswer();
  640. if (!Util.isListEmpty(qaAnswerList)) {
  641. RecyclerView answerListView = (RecyclerView) viewHolder.getView(R.id.chat_qa_msg_answer_list);
  642. LinearLayoutManager linearLayoutManager = new LinearLayoutManager(mContext);
  643. linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
  644. answerListView.setLayoutManager(linearLayoutManager);
  645. final QaAnswerAdapter qaAnswerAdapter = new QaAnswerAdapter(mContext, R.layout.item_chat_qa_answer_list, qaAnswerList);
  646. answerListView.setAdapter(qaAnswerAdapter);
  647. qaAnswerAdapter.setOnItemClickListener(new OnItemClickListener() {
  648. @Override
  649. public void onItemClick(View view, int position, RecyclerViewHolder viewHolder) {
  650. if (!mIsIntercept) {
  651. QaAnswer qaAnswer = qaAnswerAdapter.getItemByPosition(position);
  652. if (qaAnswer != null) {
  653. sendQaMessage(qaAnswer.getId());
  654. }
  655. } else {
  656. BuyServiceActivity.toBuyServiceActivity((Activity) mContext, BuyServiceActivity.INTENT_FROM_INTERCEPT,
  657. IConfigConstant.PAY_TAG_FROM_CHAT, IConfigConstant.PAY_WAY_ALL);
  658. }
  659. }
  660. });
  661. }
  662. }
  663. }
  664. }
  665. /**
  666. * 设置对方图片消息
  667. *
  668. * @param viewHolder
  669. * @param message
  670. */
  671. private void setLeftImageMsg(RecyclerViewHolder viewHolder, final Message message, final Bitmap bitmap) {
  672. if (message != null) {
  673. viewHolder.setText(R.id.chat_image_msg_time_left, TimeUtil.getLocalTime(mContext, mServerSystemTime, message.getCreateDateMills()));
  674. // 头像
  675. ImageView ivAvatar = (ImageView) viewHolder.getView(R.id.chat_image_msg_avatar_left);
  676. ImageLoaderUtil.getInstance().loadImage(mContext, new ImageLoader.Builder()
  677. .url(mAvatarUrl).transform(new CircleTransformation()).imageView(ivAvatar).build());
  678. // 点击头像可查看用户详情
  679. ivAvatar.setOnClickListener(new View.OnClickListener() {
  680. @Override
  681. public void onClick(View v) {
  682. UserInfoDetailActivity.toUserInfoDetailActivity((Activity) mContext, message.getUid(), "0", UserInfoDetailActivity.SOURCE_FROM_CHAT_CONTENT);
  683. }
  684. });
  685. final Image image = message.getChatImage();
  686. if (image != null) {
  687. ChatImageView imageView = (ChatImageView) viewHolder.getView(R.id.chat_image_msg_left);
  688. // 设置图片规格:1/3屏幕宽度,宽高比3:4
  689. int width = DensityUtil.getScreenWidth(mContext) / 3;
  690. if (bitmap != null) {
  691. int width1 = bitmap.getWidth();
  692. int height = bitmap.getHeight();
  693. Double p = height * 1.0 / width1;
  694. RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(width, (int) (p * width));
  695. layoutParams.addRule(RelativeLayout.RIGHT_OF, R.id.chat_image_msg_avatar_left);
  696. layoutParams.addRule(RelativeLayout.BELOW, R.id.chat_image_msg_time_left);
  697. // Bitmap blurBitmap =fastblur(mContext,bitmap,8);
  698. // Bitmap blurBitmap = doBlur(bitmap, 8, true);
  699. // imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
  700. // imageView.setImageBitmap(blurBitmap);
  701. imageView.setLayoutParams(layoutParams);
  702. } else {
  703. RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(width, (int) ((4 / 3.0f) * width));
  704. layoutParams.addRule(RelativeLayout.RIGHT_OF, R.id.chat_image_msg_avatar_left);
  705. layoutParams.addRule(RelativeLayout.BELOW, R.id.chat_image_msg_time_left);
  706. imageView.setLayoutParams(layoutParams);
  707. }
  708. ImageLoaderUtil.getInstance().loadImage(mContext, new ImageLoader.Builder().url(image.getThumbnailUrlM())
  709. .imageView(imageView).placeHolder(R.drawable.img_default).build());
  710. // 点击图片浏览大图
  711. imageView.setOnClickListener(new View.OnClickListener() {
  712. @Override
  713. public void onClick(View v) {
  714. PictureBrowseActivity.toPictureBrowseActivity(mContext, mAllImageList.indexOf(image), mAllImageList);
  715. }
  716. });
  717. }
  718. }
  719. }
  720. /**
  721. * 设置我方图片消息
  722. *
  723. * @param viewHolder
  724. * @param message
  725. */
  726. private void setRightImageMsg(RecyclerViewHolder viewHolder, final Message message) {
  727. if (message != null) {
  728. viewHolder.setText(R.id.chat_image_msg_time_right, TimeUtil.getLocalTime(mContext, mServerSystemTime, message.getCreateDateMills()));
  729. // 头像
  730. ImageView ivAvatar = (ImageView) viewHolder.getView(R.id.chat_image_msg_avatar_right);
  731. ImageLoaderUtil.getInstance().loadImage(mContext, new ImageLoader.Builder()
  732. .url(UserInfoXml.getAvatarUrl()).transform(new CircleTransformation()).imageView(ivAvatar).build());
  733. // 点击头像可查看用户详情
  734. ivAvatar.setOnClickListener(new View.OnClickListener() {
  735. @Override
  736. public void onClick(View v) {
  737. UserInfoDetailActivity.toUserInfoDetailActivity((Activity) mContext, message.getUid(), "0", UserInfoDetailActivity.SOURCE_FROM_CHAT_CONTENT);
  738. }
  739. });
  740. final Image image = message.getChatImage();
  741. if (image != null) {
  742. ChatImageView imageView = (ChatImageView) viewHolder.getView(R.id.chat_image_msg_right);
  743. // 设置图片规格:1/3屏幕宽度,宽高比3:4
  744. int width = DensityUtil.getScreenWidth(mContext) / 3;
  745. LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(width, (int) ((4 / 3.0f) * width));
  746. imageView.setLayoutParams(layoutParams);
  747. imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
  748. String imageUrl = image.getThumbnailUrlM();
  749. if (Utils.isHttpUrl(imageUrl)) {
  750. ImageLoaderUtil.getInstance().loadImage(mContext, new ImageLoader.Builder().url(imageUrl)
  751. .imageView(imageView).placeHolder(R.drawable.img_default).build());
  752. } else {
  753. ImageLoaderUtil.getInstance().loadLocalImage(mContext, imageView, Uri.fromFile(new File(imageUrl)));
  754. }
  755. // 点击图片浏览大图
  756. imageView.setOnClickListener(new View.OnClickListener() {
  757. @Override
  758. public void onClick(View v) {
  759. PictureBrowseActivity.toPictureBrowseActivity(mContext, mAllImageList.indexOf(image), mAllImageList);
  760. }
  761. });
  762. }
  763. // 图片加载进度
  764. final ImageView ivLoading = (ImageView) viewHolder.getView(R.id.chat_image_msg_loading);
  765. AnimationDrawable animationDrawable = Util.getFrameAnim(Utils.getLoadingDrawableList(mContext), true, 50);
  766. animationDrawable.start();
  767. ivLoading.setImageDrawable(animationDrawable);
  768. ivLoading.setVisibility(mIsShowImgLoading ? View.VISIBLE : View.GONE);
  769. // 图片重发
  770. final ImageView ivRetry = (ImageView) viewHolder.getView(R.id.chat_image_msg_retry);
  771. ivRetry.setVisibility(mIsShowImgRetry ? View.VISIBLE : View.GONE);
  772. ivRetry.setOnClickListener(new View.OnClickListener() {
  773. @Override
  774. public void onClick(View v) {
  775. // 点击重发
  776. DialogUtil.showDoubleBtnDialog(((FragmentActivity) mContext).getSupportFragmentManager(),
  777. null, mContext.getString(R.string.retry_message), mContext.getString(R.string.positive),
  778. mContext.getString(R.string.negative), true, new OnDoubleDialogClickListener() {
  779. @Override
  780. public void onPositiveClick(View view) {
  781. mIsShowImgLoading = true;
  782. mIsShowImgRetry = false;
  783. ivLoading.setVisibility(View.VISIBLE);
  784. ivRetry.setVisibility(View.GONE);
  785. sendPhotoMsg(new File(message.getChatImage().getImageUrl()), message);
  786. }
  787. @Override
  788. public void onNegativeClick(View view) {
  789. }
  790. });
  791. }
  792. });
  793. }
  794. }
  795. /**
  796. * 更新语音信已读状态
  797. *
  798. * @param msgId
  799. */
  800. private void updateVoiceMsgStatus(final String msgId) {
  801. OkHttpUtils.post()
  802. .url(IUrlConstant.URL_UPDATE_VOICE_MSG_STATUS)
  803. .addHeader("token", PlatformInfoXml.getToken())
  804. .addParams("platformInfo", PlatformInfoXml.getPlatformJsonString())
  805. .addParams("msgId", msgId)
  806. .build().execute(new Callback<BaseModel>() {
  807. @Override
  808. public BaseModel parseNetworkResponse(Response response, int id) throws Exception {
  809. String resultJson = response.body().string();
  810. if (!TextUtils.isEmpty(resultJson)) {
  811. return JSON.parseObject(resultJson, WriteMsg.class);
  812. }
  813. return null;
  814. }
  815. @Override
  816. public void onError(Call call, Exception e, int id) {
  817. // 失败后再次更新
  818. updateVoiceMsgStatus(msgId);
  819. }
  820. @Override
  821. public void onResponse(BaseModel response, int id) {
  822. if (response != null) {
  823. String isSucceed = response.getIsSucceed();
  824. if (!TextUtils.isEmpty(isSucceed) && "0".equals(isSucceed)) {
  825. // 失败后再次更新
  826. updateVoiceMsgStatus(msgId);
  827. }
  828. }
  829. }
  830. });
  831. }
  832. /**
  833. * 发送QA消息
  834. *
  835. * @param qaId
  836. */
  837. private void sendQaMessage(final String qaId) {
  838. final Dialog dialog = Utils.showLoadingDialog(mContext, true);
  839. OkHttpUtils.post()
  840. .url(IUrlConstant.URL_SEND_TEXT_MSG)
  841. .addHeader("token", PlatformInfoXml.getToken())
  842. .addParams("platformInfo", PlatformInfoXml.getPlatformJsonString())
  843. .addParams("uid", mUId)
  844. .addParams("writeMsgType", "1")
  845. .addParams("qaAnswerId", qaId)
  846. .build()
  847. .execute(new Callback<WriteMsg>() {
  848. @Override
  849. public WriteMsg parseNetworkResponse(Response response, int id) throws Exception {
  850. String resultJson = response.body().string();
  851. if (!TextUtils.isEmpty(resultJson)) {
  852. return JSON.parseObject(resultJson, WriteMsg.class);
  853. }
  854. return null;
  855. }
  856. @Override
  857. public void onError(Call call, Exception e, int id) {
  858. ToastUtil.showShortToast(mContext, mContext.getString(R.string.send_fail));
  859. if (dialog != null && dialog.isShowing()) {
  860. dialog.dismiss();
  861. }
  862. }
  863. @Override
  864. public void onResponse(WriteMsg response, int id) {
  865. if (response != null) {
  866. String isSucceed = response.getIsSucceed();
  867. if (!TextUtils.isEmpty(isSucceed) && "1".equals(isSucceed)) {
  868. // 发送事件,刷新当前聊天记录
  869. EventBus.getDefault().post(new RefreshChatEvent());
  870. // 发送事件,更新聊天列表
  871. EventBus.getDefault().post(new MessageChangedEvent());
  872. } else {
  873. ToastUtil.showShortToast(mContext, mContext.getString(R.string.send_fail));
  874. }
  875. } else {
  876. ToastUtil.showShortToast(mContext, mContext.getString(R.string.send_fail));
  877. }
  878. if (dialog != null && dialog.isShowing()) {
  879. dialog.dismiss();
  880. }
  881. }
  882. });
  883. }
  884. /**
  885. * 发送语音消息
  886. */
  887. private void sendVoiceMsg(File file, final Message message) {
  888. OkHttpUtils.post()
  889. .url(IUrlConstant.URL_SEND_VOICE_MSG)
  890. .addHeader("token", PlatformInfoXml.getToken())
  891. .addHeader("platformInfo", PlatformInfoXml.getPlatformJsonString())
  892. .addHeader("uid", mUId)
  893. .addHeader("writeMsgType", "1")
  894. .addHeader("audioSecond", message.getAudioTime())
  895. .addFile("file", file.getName(), file)
  896. .build()
  897. .execute(new Callback<BaseModel>() {
  898. @Override
  899. public BaseModel parseNetworkResponse(Response response, int id) throws Exception {
  900. String resultJson = response.body().string();
  901. if (!TextUtils.isEmpty(resultJson)) {
  902. return JSON.parseObject(resultJson, BaseModel.class);
  903. }
  904. return null;
  905. }
  906. @Override
  907. public void onError(Call call, Exception e, int id) {
  908. sendVoiceFailed(message);
  909. }
  910. @Override
  911. public void onResponse(BaseModel response, int id) {
  912. if (response != null) {
  913. String isSucceed = response.getIsSucceed();
  914. if (!TextUtils.isEmpty(isSucceed) && "1".equals(isSucceed)) {
  915. // 发送事件,刷新当前聊天记录
  916. EventBus.getDefault().post(new RefreshChatEvent());
  917. // 发送事件,更新聊天列表
  918. EventBus.getDefault().post(new MessageChangedEvent());
  919. } else {
  920. sendVoiceFailed(message);
  921. }
  922. } else {
  923. sendVoiceFailed(message);
  924. }
  925. }
  926. });
  927. }
  928. /**
  929. * 发送语音失败,刷新状态
  930. */
  931. private void sendVoiceFailed(Message message) {
  932. mIsShowVoiceLoading = false;
  933. mIsShowVoiceRetry = true;
  934. updateItem(getItemCount() - 1, message);
  935. ToastUtil.showShortToast(mContext, mContext.getString(R.string.send_fail));
  936. }
  937. /**
  938. * 发送图片消息
  939. */
  940. private void sendPhotoMsg(File file, final Message message) {
  941. OkHttpUtils.post()
  942. .url(IUrlConstant.URL_SEND_PHOTO_MSG)
  943. .addHeader("token", PlatformInfoXml.getToken())
  944. .addHeader("platformInfo", PlatformInfoXml.getPlatformJsonString())
  945. .addHeader("recevUserId", mUId)
  946. .addFile("request", file.getName(), file)
  947. .build()
  948. .execute(new Callback<BaseModel>() {
  949. @Override
  950. public BaseModel parseNetworkResponse(Response response, int id) throws Exception {
  951. String resultJson = response.body().string();
  952. if (!TextUtils.isEmpty(resultJson)) {
  953. return JSON.parseObject(resultJson, BaseModel.class);
  954. }
  955. return null;
  956. }
  957. @Override
  958. public void onError(Call call, Exception e, int id) {
  959. sendPhotoFailed(message);
  960. }
  961. @Override
  962. public void onResponse(BaseModel response, int id) {
  963. if (response != null) {
  964. String isSucceed = response.getIsSucceed();
  965. if (!TextUtils.isEmpty(isSucceed) && "1".equals(isSucceed)) {
  966. // 发送事件,刷新当前聊天记录
  967. EventBus.getDefault().post(new RefreshChatEvent());
  968. // 发送事件,更新聊天列表
  969. EventBus.getDefault().post(new MessageChangedEvent());
  970. } else {
  971. sendPhotoFailed(message);
  972. }
  973. } else {
  974. sendPhotoFailed(message);
  975. }
  976. }
  977. });
  978. }
  979. /**
  980. * 发送图片失败,刷新状态
  981. */
  982. private void sendPhotoFailed(Message message) {
  983. mIsShowImgLoading = false;
  984. mIsShowImgRetry = true;
  985. updateItem(getItemCount() - 1, message);
  986. ToastUtil.showShortToast(mContext, mContext.getString(R.string.send_fail));
  987. }
  988. /**
  989. * 根据图片的url路径获得Bitmap对象
  990. *
  991. * @param url
  992. * @return
  993. */
  994. public void returnBitmap(final String url, final RecyclerViewHolder viewHolder, final Message bean) {
  995. AsyncTask task = new AsyncTask() {
  996. @Override
  997. protected Object doInBackground(Object[] objects) {
  998. URL fileUrl = null;
  999. Bitmap bitmap = null;
  1000. try {
  1001. fileUrl = new URL(url);
  1002. } catch (MalformedURLException e) {
  1003. e.printStackTrace();
  1004. }
  1005. try {
  1006. HttpURLConnection conn = (HttpURLConnection) fileUrl
  1007. .openConnection();
  1008. conn.setDoInput(true);
  1009. conn.connect();
  1010. InputStream is = conn.getInputStream();
  1011. bitmap = BitmapFactory.decodeStream(is);
  1012. is.close();
  1013. } catch (IOException e) {
  1014. e.printStackTrace();
  1015. }
  1016. return bitmap;
  1017. }
  1018. @Override
  1019. protected void onPostExecute(Object o) {
  1020. super.onPostExecute(o);
  1021. Bitmap bitmap = (Bitmap) o;
  1022. setLeftImageMsg(viewHolder, bean, bitmap);
  1023. }
  1024. }.execute();
  1025. }
  1026. /**毛玻璃效果**/
  1027. public static Bitmap doBlur(Bitmap sentBitmap, int radius, boolean canReuseInBitmap) {
  1028. // Stack Blur v1.0 from
  1029. // http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html
  1030. //
  1031. // Java Author: Mario Klingemann <mario at quasimondo.com>
  1032. // http://incubator.quasimondo.com
  1033. // created Feburary 29, 2004
  1034. // Android port : Yahel Bouaziz <yahel at kayenko.com>
  1035. // http://www.kayenko.com
  1036. // ported april 5th, 2012
  1037. // This is a compromise between Gaussian Blur and Box blur
  1038. // It creates much better looking blurs than Box Blur, but is
  1039. // 7x faster than my Gaussian Blur implementation.
  1040. //
  1041. // I called it Stack Blur because this describes best how this
  1042. // filter works internally: it creates a kind of moving stack
  1043. // of colors whilst scanning through the image. Thereby it
  1044. // just has to add one new block of color to the right side
  1045. // of the stack and remove the leftmost color. The remaining
  1046. // colors on the topmost layer of the stack are either added on
  1047. // or reduced by one, depending on if they are on the right or
  1048. // on the left side of the stack.
  1049. //
  1050. // If you are using this algorithm in your code please add
  1051. // the following line:
  1052. //
  1053. // Stack Blur Algorithm by Mario Klingemann <mario@quasimondo.com>
  1054. Bitmap bitmap;
  1055. if (canReuseInBitmap) {
  1056. bitmap = sentBitmap;
  1057. } else {
  1058. bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
  1059. }
  1060. if (radius < 1) {
  1061. return (null);
  1062. }
  1063. int w = bitmap.getWidth();
  1064. int h = bitmap.getHeight();
  1065. int[] pix = new int[w * h];
  1066. bitmap.getPixels(pix, 0, w, 0, 0, w, h);
  1067. int wm = w - 1;
  1068. int hm = h - 1;
  1069. int wh = w * h;
  1070. int div = radius + radius + 1;
  1071. int r[] = new int[wh];
  1072. int g[] = new int[wh];
  1073. int b[] = new int[wh];
  1074. int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
  1075. int vmin[] = new int[Math.max(w, h)];
  1076. int divsum = (div + 1) >> 1;
  1077. divsum *= divsum;
  1078. int dv[] = new int[256 * divsum];
  1079. for (i = 0; i < 256 * divsum; i++) {
  1080. dv[i] = (i / divsum);
  1081. }
  1082. yw = yi = 0;
  1083. int[][] stack = new int[div][3];
  1084. int stackpointer;
  1085. int stackstart;
  1086. int[] sir;
  1087. int rbs;
  1088. int r1 = radius + 1;
  1089. int routsum, goutsum, boutsum;
  1090. int rinsum, ginsum, binsum;
  1091. for (y = 0; y < h; y++) {
  1092. rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
  1093. for (i = -radius; i <= radius; i++) {
  1094. p = pix[yi + Math.min(wm, Math.max(i, 0))];
  1095. sir = stack[i + radius];
  1096. sir[0] = (p & 0xff0000) >> 16;
  1097. sir[1] = (p & 0x00ff00) >> 8;
  1098. sir[2] = (p & 0x0000ff);
  1099. rbs = r1 - Math.abs(i);
  1100. rsum += sir[0] * rbs;
  1101. gsum += sir[1] * rbs;
  1102. bsum += sir[2] * rbs;
  1103. if (i > 0) {
  1104. rinsum += sir[0];
  1105. ginsum += sir[1];
  1106. binsum += sir[2];
  1107. } else {
  1108. routsum += sir[0];
  1109. goutsum += sir[1];
  1110. boutsum += sir[2];
  1111. }
  1112. }
  1113. stackpointer = radius;
  1114. for (x = 0; x < w; x++) {
  1115. r[yi] = dv[rsum];
  1116. g[yi] = dv[gsum];
  1117. b[yi] = dv[bsum];
  1118. rsum -= routsum;
  1119. gsum -= goutsum;
  1120. bsum -= boutsum;
  1121. stackstart = stackpointer - radius + div;
  1122. sir = stack[stackstart % div];
  1123. routsum -= sir[0];
  1124. goutsum -= sir[1];
  1125. boutsum -= sir[2];
  1126. if (y == 0) {
  1127. vmin[x] = Math.min(x + radius + 1, wm);
  1128. }
  1129. p = pix[yw + vmin[x]];
  1130. sir[0] = (p & 0xff0000) >> 16;
  1131. sir[1] = (p & 0x00ff00) >> 8;
  1132. sir[2] = (p & 0x0000ff);
  1133. rinsum += sir[0];
  1134. ginsum += sir[1];
  1135. binsum += sir[2];
  1136. rsum += rinsum;
  1137. gsum += ginsum;
  1138. bsum += binsum;
  1139. stackpointer = (stackpointer + 1) % div;
  1140. sir = stack[(stackpointer) % div];
  1141. routsum += sir[0];
  1142. goutsum += sir[1];
  1143. boutsum += sir[2];
  1144. rinsum -= sir[0];
  1145. ginsum -= sir[1];
  1146. binsum -= sir[2];
  1147. yi++;
  1148. }
  1149. yw += w;
  1150. }
  1151. for (x = 0; x < w; x++) {
  1152. rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
  1153. yp = -radius * w;
  1154. for (i = -radius; i <= radius; i++) {
  1155. yi = Math.max(0, yp) + x;
  1156. sir = stack[i + radius];
  1157. sir[0] = r[yi];
  1158. sir[1] = g[yi];
  1159. sir[2] = b[yi];
  1160. rbs = r1 - Math.abs(i);
  1161. rsum += r[yi] * rbs;
  1162. gsum += g[yi] * rbs;
  1163. bsum += b[yi] * rbs;
  1164. if (i > 0) {
  1165. rinsum += sir[0];
  1166. ginsum += sir[1];
  1167. binsum += sir[2];
  1168. } else {
  1169. routsum += sir[0];
  1170. goutsum += sir[1];
  1171. boutsum += sir[2];
  1172. }
  1173. if (i < hm) {
  1174. yp += w;
  1175. }
  1176. }
  1177. yi = x;
  1178. stackpointer = radius;
  1179. for (y = 0; y < h; y++) {
  1180. // Preserve alpha channel: ( 0xff000000 & pix[yi] )
  1181. pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum];
  1182. rsum -= routsum;
  1183. gsum -= goutsum;
  1184. bsum -= boutsum;
  1185. stackstart = stackpointer - radius + div;
  1186. sir = stack[stackstart % div];
  1187. routsum -= sir[0];
  1188. goutsum -= sir[1];
  1189. boutsum -= sir[2];
  1190. if (x == 0) {
  1191. vmin[y] = Math.min(y + r1, hm) * w;
  1192. }
  1193. p = x + vmin[y];
  1194. sir[0] = r[p];
  1195. sir[1] = g[p];
  1196. sir[2] = b[p];
  1197. rinsum += sir[0];
  1198. ginsum += sir[1];
  1199. binsum += sir[2];
  1200. rsum += rinsum;
  1201. gsum += ginsum;
  1202. bsum += binsum;
  1203. stackpointer = (stackpointer + 1) % div;
  1204. sir = stack[stackpointer];
  1205. routsum += sir[0];
  1206. goutsum += sir[1];
  1207. boutsum += sir[2];
  1208. rinsum -= sir[0];
  1209. ginsum -= sir[1];
  1210. binsum -= sir[2];
  1211. yi += w;
  1212. }
  1213. }
  1214. bitmap.setPixels(pix, 0, w, 0, 0, w, h);
  1215. return (bitmap);
  1216. }
  1217. public Bitmap fastblur(Context context, Bitmap sentBitmap, int radius) {
  1218. if (Build.VERSION.SDK_INT > 16) {
  1219. Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
  1220. final RenderScript rs = RenderScript.create(context);
  1221. final Allocation input = Allocation.createFromBitmap(rs, sentBitmap, Allocation.MipmapControl.MIPMAP_NONE,
  1222. Allocation.USAGE_SCRIPT);
  1223. final Allocation output = Allocation.createTyped(rs, input.getType());
  1224. final ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
  1225. script.setRadius(radius /* e.g. 3.f */);
  1226. script.setInput(input);
  1227. script.forEach(output);
  1228. output.copyTo(bitmap);
  1229. return bitmap;
  1230. }
  1231. Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
  1232. if (radius < 1) {
  1233. return (null);
  1234. }
  1235. int w = bitmap.getWidth();
  1236. int h = bitmap.getHeight();
  1237. int[] pix = new int[w * h];
  1238. bitmap.getPixels(pix, 0, w, 0, 0, w, h);
  1239. int wm = w - 1;
  1240. int hm = h - 1;
  1241. int wh = w * h;
  1242. int div = radius + radius + 1;
  1243. int r[] = new int[wh];
  1244. int g[] = new int[wh];
  1245. int b[] = new int[wh];
  1246. int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
  1247. int vmin[] = new int[Math.max(w, h)];
  1248. int divsum = (div + 1) >> 1;
  1249. divsum *= divsum;
  1250. int temp = 256 * divsum;
  1251. int dv[] = new int[temp];
  1252. for (i = 0; i < temp; i++) {
  1253. dv[i] = (i / divsum);
  1254. }
  1255. yw = yi = 0;
  1256. int[][] stack = new int[div][3];
  1257. int stackpointer;
  1258. int stackstart;
  1259. int[] sir;
  1260. int rbs;
  1261. int r1 = radius + 1;
  1262. int routsum, goutsum, boutsum;
  1263. int rinsum, ginsum, binsum;
  1264. for (y = 0; y < h; y++) {
  1265. rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
  1266. for (i = -radius; i <= radius; i++) {
  1267. p = pix[yi + Math.min(wm, Math.max(i, 0))];
  1268. sir = stack[i + radius];
  1269. sir[0] = (p & 0xff0000) >> 16;
  1270. sir[1] = (p & 0x00ff00) >> 8;
  1271. sir[2] = (p & 0x0000ff);
  1272. rbs = r1 - Math.abs(i);
  1273. rsum += sir[0] * rbs;
  1274. gsum += sir[1] * rbs;
  1275. bsum += sir[2] * rbs;
  1276. if (i > 0) {
  1277. rinsum += sir[0];
  1278. ginsum += sir[1];
  1279. binsum += sir[2];
  1280. } else {
  1281. routsum += sir[0];
  1282. goutsum += sir[1];
  1283. boutsum += sir[2];
  1284. }
  1285. }
  1286. stackpointer = radius;
  1287. for (x = 0; x < w; x++) {
  1288. r[yi] = dv[rsum];
  1289. g[yi] = dv[gsum];
  1290. b[yi] = dv[bsum];
  1291. rsum -= routsum;
  1292. gsum -= goutsum;
  1293. bsum -= boutsum;
  1294. stackstart = stackpointer - radius + div;
  1295. sir = stack[stackstart % div];
  1296. routsum -= sir[0];
  1297. goutsum -= sir[1];
  1298. boutsum -= sir[2];
  1299. if (y == 0) {
  1300. vmin[x] = Math.min(x + radius + 1, wm);
  1301. }
  1302. p = pix[yw + vmin[x]];
  1303. sir[0] = (p & 0xff0000) >> 16;
  1304. sir[1] = (p & 0x00ff00) >> 8;
  1305. sir[2] = (p & 0x0000ff);
  1306. rinsum += sir[0];
  1307. ginsum += sir[1];
  1308. binsum += sir[2];
  1309. rsum += rinsum;
  1310. gsum += ginsum;
  1311. bsum += binsum;
  1312. stackpointer = (stackpointer + 1) % div;
  1313. sir = stack[(stackpointer) % div];
  1314. routsum += sir[0];
  1315. goutsum += sir[1];
  1316. boutsum += sir[2];
  1317. rinsum -= sir[0];
  1318. ginsum -= sir[1];
  1319. binsum -= sir[2];
  1320. yi++;
  1321. }
  1322. yw += w;
  1323. }
  1324. for (x = 0; x < w; x++) {
  1325. rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
  1326. yp = -radius * w;
  1327. for (i = -radius; i <= radius; i++) {
  1328. yi = Math.max(0, yp) + x;
  1329. sir = stack[i + radius];
  1330. sir[0] = r[yi];
  1331. sir[1] = g[yi];
  1332. sir[2] = b[yi];
  1333. rbs = r1 - Math.abs(i);
  1334. rsum += r[yi] * rbs;
  1335. gsum += g[yi] * rbs;
  1336. bsum += b[yi] * rbs;
  1337. if (i > 0) {
  1338. rinsum += sir[0];
  1339. ginsum += sir[1];
  1340. binsum += sir[2];
  1341. } else {
  1342. routsum += sir[0];
  1343. goutsum += sir[1];
  1344. boutsum += sir[2];
  1345. }
  1346. if (i < hm) {
  1347. yp += w;
  1348. }
  1349. }
  1350. yi = x;
  1351. stackpointer = radius;
  1352. for (y = 0; y < h; y++) {
  1353. pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16)
  1354. | (dv[gsum] << 8) | dv[bsum];
  1355. rsum -= routsum;
  1356. gsum -= goutsum;
  1357. bsum -= boutsum;
  1358. stackstart = stackpointer - radius + div;
  1359. sir = stack[stackstart % div];
  1360. routsum -= sir[0];
  1361. goutsum -= sir[1];
  1362. boutsum -= sir[2];
  1363. if (x == 0) {
  1364. vmin[y] = Math.min(y + r1, hm) * w;
  1365. }
  1366. p = x + vmin[y];
  1367. sir[0] = r[p];
  1368. sir[1] = g[p];
  1369. sir[2] = b[p];
  1370. rinsum += sir[0];
  1371. ginsum += sir[1];
  1372. binsum += sir[2];
  1373. rsum += rinsum;
  1374. gsum += ginsum;
  1375. bsum += binsum;
  1376. stackpointer = (stackpointer + 1) % div;
  1377. sir = stack[stackpointer];
  1378. routsum += sir[0];
  1379. goutsum += sir[1];
  1380. boutsum += sir[2];
  1381. rinsum -= sir[0];
  1382. ginsum -= sir[1];
  1383. binsum -= sir[2];
  1384. yi += w;
  1385. }
  1386. }
  1387. bitmap.setPixels(pix, 0, w, 0, 0, w, h);
  1388. return (bitmap);
  1389. }
  1390. }