彩信相关,还需要处理,没怎么写注释,不适合无相关经验的

package 列表处理dao;

import android.content.ContentUris;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.provider.Telephony;
import android.util.Log;
import android.widget.Toast;

import com.android.mms.MmsApp;
import com.android.mms.R;
import com.android.mms.data.Contact;
import com.android.mms.data.RecipientIdCache;
import com.android.mms.data.WorkingMessage;
import com.android.mms.model.SlideshowModel;
import com.google.android.mms.pdu.PduBody;
import com.vogtec.sdk.utils.L;
import com.vogtec.sms.MmsListActivity;
import com.vogtec.sms.Tools.CustomThreadPool;
import com.vogtec.sms.Tools.FileUtils;
import com.vogtec.sms.bean.MmsBean;

import java.util.ArrayList;
import java.util.List;

/**
 * 彩信数据管理
 * Create by Sage Luo
 * on 2020/12/16 0016 09:02
 */
public class MmsDao {
	private final static Uri CONTENT_URI_PART = Uri.parse("content://mms/part"); //彩信附件表
	private static final MmsDao instance = new MmsDao();
//	private final Map<String, MmsBean> mmsBeanMap = new HashMap<>();
	private List<MmsBean> mmsBeanList = new ArrayList<>();
	private OnMmsChangeListener onMmsChangeListener;
	private boolean isInit;
	private MmsContentObserver mmsContentObserver;

	public static MmsDao getInstance() {
		return instance;
	}

	public void init (Context context) {
		if (!isInit) {
			updateAll(context);
			mmsContentObserver =  new MmsContentObserver(new Handler(context.getApplicationContext().getMainLooper()), context);
			context.getApplicationContext().getContentResolver().registerContentObserver(Telephony.Mms.Inbox.CONTENT_URI, true, mmsContentObserver);
			isInit = true;
		}
	}

	public void updateAll(Context context) {
		mmsBeanList.clear();
		CustomThreadPool.get().execute(() -> {
			try (Cursor cursor = context.getApplicationContext().getContentResolver().query(Telephony.Mms.Inbox.CONTENT_URI, null, null, null, "date desc")) {
				int count = 0;
				if (cursor.moveToFirst()) {
					do {
//						Log.e("Sage Text", "count = " + (++count));
						int idColumn = cursor.getColumnIndex("_id");
						int threadIdColumn = cursor.getColumnIndex("thread_id");
						int dateColumn = cursor.getColumnIndex("date");
//			int msgBoxColumn = cursor.getColumnIndex("msg_box");
						int readColumn = cursor.getColumnIndex("read");
//			int seenColumn = cursor.getColumnIndex("seen");
						long id = cursor.getInt(idColumn);
						long threadId = cursor.getLong(threadIdColumn);
						long date = cursor.getLong(dateColumn) * 1000;
						int read = cursor.getInt(readColumn);
						String subject = cursor.getString(cursor.getColumnIndex("sub"));//彩信主题
						String address = RecipientIdCache.getSingleAddressFromCanonicalAddressInDb(context, threadId + "");
						boolean isHasVideo = false;
						boolean isHasAudio = false;
						boolean isHasImage = false;
						String bodyStr = "";
						try (Cursor cPart = context.getContentResolver().query(CONTENT_URI_PART, null, "mid=?", new String[]{String.valueOf(id)}, null)) {
							//根据彩信ID查询彩信的附件
							String[] coloumns;
							String[] values = null;
							if (cPart.moveToFirst()) {
								do {
									coloumns = cPart.getColumnNames();
									if (values == null)
										values = new String[coloumns.length];
									for (int i = 0; i < cPart.getColumnCount(); i++) {
										values[i] = cPart.getString(i);
									}
									if (values[3].startsWith("text/")) { // 文字
										// 获取彩信文字
										if (values[12] != null) {//所以该处需判断一下,如果_date为null,可直接设置内容为"text"
											bodyStr = FileUtils.getMmsText(values[0], context);
										} else {
											bodyStr = values[13];
										}
									} else if (values[3].startsWith("image/")) {//图片附件
										isHasImage = true;
									} else if (values[3].startsWith("audio/")) { // 音频附件
										isHasAudio = true;
									} else if (values[3].startsWith("video/")) { // 视频附件
										isHasVideo = true;
									}
								} while (cPart.moveToNext());
							}
						} catch (RuntimeException e) {
							L.e(e.getMessage());
						}
						String sender = Contact.get(address, false).getName();
						String phone = Contact.get(address, false).getNumber();
						MmsBean mmsBean = new MmsBean(id, read, date, subject, sender, phone);
						mmsBean.setPartContent(bodyStr);
						mmsBean.setHasVideo(isHasVideo);
						mmsBean.setHasAudio(isHasAudio);
						mmsBean.setHasImage(isHasImage);
						mmsBean.setThreadId(threadId);
						mmsBeanList.add(mmsBean);
						if ((++count) % 10 == 0)
							notifyDataChanged(context, false);
					} while (cursor.moveToNext());
					if (mmsBeanList.size() > 0 && (count % 10) != 0)
					notifyDataChanged(context, false);
				}
			} catch (Exception e) {
				e.printStackTrace();
			}

		});

	}

	private void notifyDataChanged(Context context, boolean isNew) {
		new Handler(context.getMainLooper()).post(() -> {
			if (onMmsChangeListener != null) {
				onMmsChangeListener.mmsChanged(mmsBeanList, isNew);
			}
		});
	}

	/**
	 * 获取彩信数据集合
	 */
	public List<MmsBean> getMmsBeanList(Context context) {
		if (!isInit) {
			init(context);
		} else if (mmsBeanList.size() == 0) {
			updateAll(context);
		}
		return mmsBeanList;
	}

	public interface OnMmsChangeListener {
		void mmsChanged(List<MmsBean> mmsBeanList, boolean isNew);
	}

	public void setOnMmsChangeListener(OnMmsChangeListener onMmsChangeListener) {
		this.onMmsChangeListener = onMmsChangeListener;
	}

	private static class MmsContentObserver extends ContentObserver {
//		content://mms/1608170134281/part 附件标志
		private final Context context;
		private boolean isHasPart;

		public MmsContentObserver(Handler handler, Context context) {
			super(handler);
			this.context = context;
		}

		@Override
		public void onChange(boolean selfChange, Uri uri) {
			super.onChange(selfChange, uri);
			Log.i("Sage Test", "uri = " + uri);
			if (uri != null) {
				if (uri.toString().startsWith("content://mms/inbox") && isHasPart) {
					isHasPart = false;
					CustomThreadPool.get().execute(() -> instance.updateByUri(uri, context));
				} else if (uri.toString().startsWith("content://mms") && uri.toString().endsWith("/part"))
					isHasPart = true;
				else if (uri.toString().startsWith("content://mms/outbox"))
					Toast.makeText(context, R.string.strOk, Toast.LENGTH_SHORT).show();

			}

		}
	}

	private void updateByUri(Uri uri, Context context) {
		try (Cursor cursor = context.getContentResolver().query(uri, null, null, null)) {
			if (cursor.moveToFirst()) {
				int idColumn = cursor.getColumnIndex("_id");
				int threadIdColumn = cursor.getColumnIndex("thread_id");
				int dateColumn = cursor.getColumnIndex("date");
//			int msgBoxColumn = cursor.getColumnIndex("msg_box");
				int readColumn = cursor.getColumnIndex("read");
				long id = cursor.getInt(idColumn);
				long threadId = cursor.getLong(threadIdColumn);
				long date = cursor.getLong(dateColumn) * 1000;
				int read = cursor.getInt(readColumn);
				String subject = cursor.getString(cursor.getColumnIndex("sub"));//彩信主题
				String address = RecipientIdCache.getSingleAddressFromCanonicalAddressInDb(context, threadId + "");
				boolean isHasVideo = false;
				boolean isHasAudio = false;
				boolean isHasImage = false;
				String bodyStr = "";
				try (Cursor cPart = context.getContentResolver().query(CONTENT_URI_PART, null, "mid=?", new String[]{String.valueOf(id)}, null)) {
					//根据彩信ID查询彩信的附件
					String[] coloumns;
					String[] values = null;
					if (cPart.moveToFirst()) {
						do {
							coloumns = cPart.getColumnNames();
							if (values == null)
								values = new String[coloumns.length];
							for (int i = 0; i < cPart.getColumnCount(); i++) {
								values[i] = cPart.getString(i);
							}
							if (values[3].startsWith("text/")) { // 文字
								// 获取彩信文字
								if (values[12] != null) {//所以该处需判断一下,如果_date为null,可直接设置内容为"text"
									bodyStr = FileUtils.getMmsText(values[0], context);
								} else {
									bodyStr = values[13];
								}
							} else if (values[3].startsWith("image/")) {//图片附件
								isHasImage = true;
							} else if (values[3].startsWith("audio/")) { // 音频附件
								isHasAudio = true;
							} else if (values[3].startsWith("video/")) { // 视频附件
								isHasVideo = true;
							}
						} while (cPart.moveToNext());
					}
				} catch (RuntimeException e) {
					L.e(e.getMessage());
				}
				String sender = Contact.get(address, false).getName();
				String phone = Contact.get(address, false).getNumber();
				MmsBean mmsBean = new MmsBean(id, read, date, subject, sender, phone);
				mmsBean.setPartContent(bodyStr);
				mmsBean.setHasVideo(isHasVideo);
				mmsBean.setHasAudio(isHasAudio);
				mmsBean.setHasImage(isHasImage);
				mmsBean.setThreadId(threadId);
				boolean isHas = false;
				for (int i = 0; i < mmsBeanList.size(); i++) {
					MmsBean mb = mmsBeanList.get(i);
					if (mb.getId() == id) {
						mmsBeanList.set(i, mmsBean);
						isHas = true;
						break;
					}
				}
				if (!isHas) {
					List<MmsBean> cacheList = new ArrayList<>();
					cacheList.add(mmsBean);
					cacheList.addAll(mmsBeanList);
					mmsBeanList = cacheList;
				}
			}
			notifyDataChanged(context, true);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void unregisterMmsDao(Context context) {
		if (mmsContentObserver != null)
			context.getApplicationContext().getContentResolver().unregisterContentObserver(mmsContentObserver);
	}

	public void deleteOneData(Context context, long _id) {
		CustomThreadPool.get().execute(() -> {
			try {
				PduBody body = null;
				SlideshowModel slideModels = null;
				try {
					body = SlideshowModel.getPduBody(context, ContentUris.withAppendedId(Telephony.Mms.Inbox.CONTENT_URI, _id));
					slideModels = SlideshowModel.createFromPduBody(context, body);
					WorkingMessage.removeThumbnailsFromCache(slideModels);
					MmsApp.getApplication().getPduLoaderManager().
							removePdu(ContentUris.withAppendedId(Telephony.Mms.Inbox.CONTENT_URI, _id));
					context.getContentResolver().delete(ContentUris.withAppendedId(Telephony.Mms.Inbox.CONTENT_URI, _id), null, null);
				} catch (Exception e) {
					e.printStackTrace();
				}
				updateAll(context);
			} catch (Exception e) {
				e.printStackTrace();
			}

		});

	}

	public void deleteAllData(Context context) {
		CustomThreadPool.get().execute(() -> {
			try {
				for (MmsBean mmsBean : mmsBeanList) {
					PduBody body = null;
					SlideshowModel slideModels = null;
					try {
						body = SlideshowModel.getPduBody(context, ContentUris.withAppendedId(Telephony.Mms.Inbox.CONTENT_URI, mmsBean.getId()));
						slideModels = SlideshowModel.createFromPduBody(context, body);
						WorkingMessage.removeThumbnailsFromCache(slideModels);
						MmsApp.getApplication().getPduLoaderManager().
								removePdu(ContentUris.withAppendedId(Telephony.Mms.Inbox.CONTENT_URI, mmsBean.getId()));
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				updateAll(context);
			} catch (Exception e) {
				e.printStackTrace();
			}

		});

	}
}
package 彩信显示;

import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Movie;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.provider.ContactsContract;
import android.provider.Telephony;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListPopupWindow;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.VideoView;

import com.android.mms.R;
import com.android.mms.data.WorkingMessage;
import com.vogtec.sdk.constans.MM;
import com.vogtec.sdk.ui.activity.BaseActivity;
import com.vogtec.sdk.ui.view.GifView;
import com.vogtec.sdk.utils.AppUtils;
import com.vogtec.sdk.utils.L;
import com.vogtec.sdk.utils.T;
import com.vogtec.sdk.utils.Utils;
import com.vogtec.sdk.view.MyEditTextView;
import com.vogtec.sms.Tools.BitmapTools;
import com.vogtec.sms.Tools.CustomThreadPool;
import com.vogtec.sms.Tools.FileUtils;
import com.vogtec.sms.Tools.MmsTools;
import com.vogtec.sms.Tools.SmsTools;
import com.vogtec.sms.bean.MediaRecognize;
import com.vogtec.sms.bean.MmsBean;
import com.vogtec.sms.bean.MmsMediaPart;
import com.vogtec.sms.dao.MmsDao;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 彩信收件箱
 * Create by Sage Luo
 * on 2020/12/15 0015 14:04
 */
public class MmsDetailActivity_2 extends BaseActivity {
	private TextView tvName, tvSubTitle, tvPhoneNum;
	private MmsBean mmsBean;
	private LinearLayout llMedia;
	private final List<Bitmap> bitmapList = new ArrayList<>();
	private int screenWidth, screenHeight;
	private RelativeLayout rlMmsDetail;
	private MediaRecognize videoRecognize;
	private MediaRecognize audioRecognize;
	private MediaRecognize imageRecognize;

	private VideoView videoView;
	private FrameLayout flMedia;

	//	private final Uri CONTENT_URI = Uri.parse("content://mms/inbox"); //彩信收件箱
	private final static Uri CONTENT_URI_PART = Uri.parse("content://mms/part"); //彩信附件表
	/**
	 * typeTag:(1:收件箱,2:发件箱,3:草稿箱)
	 */
	public static final String TYPE_TAG = "typeTag";
	private final static int[] MENU_NORMAL = {R.string.replay_sms, R.string.sned_sms, R.string.forward_sms, R.string.make_call, R.string.delete};
	private final static int[] MENU_WITH_MEDIA = {R.string.play, R.string.replay_sms, R.string.forward_sms, R.string.sned_sms, R.string.make_call, R.string.delete};

	private AnimationDrawable audioAnimation;
	private MediaPlayer audioPlayer;
	private final StringBuilder stringBuilder = new StringBuilder();
	private final List<MmsMediaPart> mediaParts = new ArrayList<>();

	private List<MmsMediaPart> audios = new ArrayList<>();
	private List<MmsMediaPart> videos = new ArrayList<>();
	private List<MmsMediaPart> gifs = new ArrayList<>();
	private List<MmsMediaPart> pictures = new ArrayList<>();
	private Bitmap[] imageBitmaps;

	private RelativeLayout rlInputRecipient;
	private MyEditTextView etTo;
	private ListPopupWindow mPopup;
	private TextView tips;
	final ArrayList<ContactBean> contactBeans = new ArrayList<>();
	private int fromType = 0;
	private FilterTask filterTask = new FilterTask();
	private final MyAdapter adapter = new MyAdapter(contactBeans);
	private final static int PRE_MESSAGE_SENT = 0x111;
	private final static int MESSAGE_SENT = 0x112;
	private final static int PENDING_MESSAGES_REACHED = 0x113;
	private final static int ATTACHMENT_ERROR = 0x114;
	private final static int PRE_MMS_SENT = 0x115;
//	private boolean isExcuting;
//	private boolean isExcuteCancel;

	@Override
	protected int getLayoutResId() {
		return R.layout.activity_mms_detail_2;
	}

	@Override
	protected void initHeadBtmAndView() {
		tvName = findView(R.id.tv_name);
		tvPhoneNum = findView(R.id.tvPhoneNum);
		tvSubTitle = findView(R.id.tvSubTitle);
		llMedia = findView(R.id.llMedia);
		rlMmsDetail = findView(R.id.rlMmsDetail);

		rlInputRecipient = findViewById(R.id.rlInputRecipient);
		tips = findViewById(R.id.tips);
		etTo = findView(R.id.et_number);

		setBtmLeftRightString(R.string.menu, R.string.back);
		initData();
	}

	private void initData() {
		mmsBean = (MmsBean) getIntent().getSerializableExtra("data");
		showMms(this);

		tvName.setText(mmsBean.getSender());
		tvPhoneNum.setText(mmsBean.getPhone());
		if (!TextUtils.isEmpty(mmsBean.getSubject())) {
			tvSubTitle.setText(mmsBean.getSubject());
			tvSubTitle.setVisibility(View.VISIBLE);
		}
		int[] screenSize = getScreenSize();
		screenWidth = screenSize[0];
		screenHeight = screenSize[1];
		initContact();
	}

	private void showMms(Context context) {
		CustomThreadPool.get().execute(() -> {
			ContentValues cvs = new ContentValues();
			cvs.put("read", 1);
			getContentResolver().update(Telephony.Mms.CONTENT_URI, cvs, "_id=?", new String[]{String.valueOf(mmsBean.getId())});

			List<Bitmap> bitmaps = new ArrayList<>();

			try (Cursor cPart = getContentResolver().query(CONTENT_URI_PART, null, "mid=?", new String[]{String.valueOf(mmsBean.getId())}, null)) {
				//根据彩信ID查询彩信的附件
				String bodyStr = "";
				String[] coloumns;
				String[] values = null;
				int count = 0;
				if (cPart.moveToFirst()) {
					do {
						coloumns = cPart.getColumnNames();
						if (values == null)
							values = new String[coloumns.length];
						for (int i = 0; i < cPart.getColumnCount(); i++) {
							values[i] = cPart.getString(i);
						}
						if (values[3].startsWith("text/")) { // 文字
							// 获取彩信文字
							if (values[12] != null) {//所以该处需判断一下,如果_date为null,可直接设置内容为"text"
								bodyStr = FileUtils.getMmsText(values[0], MmsDetailActivity_2.this);
							} else {
								bodyStr = values[13];
							}
							showContent(bodyStr);
						} else if (values[3].startsWith("image/")) {//图片附件
							if (values[3].equals("image/gif")) {
								showGif(values[0]);
							} else {
								Bitmap bitmap = getMmsImage(values[0]);
								bitmaps.add(bitmap);
								if (bitmap == null) continue;
								int[] size = getBetterSize(bitmap.getWidth(), bitmap.getHeight());
								if (size[2] > 1) {
									bitmap = BitmapTools.getBitmap(bitmap, size[2]);
								}
								showBitmap(size[0], size[1], bitmap);
							}
						} else if (values[3].startsWith("audio/")) { // 音频附件
//							getAudio(values[0], values[4]);
							showAudioUi(values[0]);
						} else if (values[3].startsWith("video/")) { // 视频附件
							Bitmap thumbnail = BitmapTools.getVideoThumbnailPicture(context, Uri.parse("content://mms/part/" + values[0]));
							showVideoUi(values[0], thumbnail);
						}
						if (!values[3].equals("application/smil") && !values[3].startsWith("text/")) {
							addMediaPart(values[0], values[3], values[4], bitmaps);
						}
					} while (cPart.moveToNext());
				}
			} catch (RuntimeException e) {
				L.e(e.getMessage());
			}
		});

	}

	private void addMediaPart(String _id, String mediaType, String mediaName, List<Bitmap> bitmaps) {
		Uri partURI = Uri.parse("content://mms/part/" + _id );
		try (InputStream is = getContentResolver().openInputStream(partURI)) {
			byte[] bytes = FileUtils.getBytesByInputStream(is);
			MmsDetailActivity_2.this.runOnUiThread(() -> {
				MmsMediaPart mmsMediaPart = new MmsMediaPart(bytes, mediaType, mediaName, partURI);
				if (mediaType.startsWith("audio/")) {
					audios.add(mmsMediaPart);
					mmsMediaPart.setAttachmentType(WorkingMessage.AUDIO);
				} else if (mediaType.startsWith("video/")) {
					videos.add(mmsMediaPart);
					mmsMediaPart.setAttachmentType(WorkingMessage.VIDEO);
				} else if (mediaType.equals("image/gif")) {
					gifs.add(mmsMediaPart);
					mmsMediaPart.setAttachmentType(WorkingMessage.IMAGE);
				} else if ((mediaType.startsWith("image/"))) {
					imageBitmaps = new Bitmap[bitmaps.size()];
					for (int i = 0; i < imageBitmaps.length; i++) {
						imageBitmaps[i] = bitmaps.get(i);
					}
					pictures.add(mmsMediaPart);
					mmsMediaPart.setAttachmentType(WorkingMessage.IMAGE);
				} else if (mediaType.startsWith("text/")) {
					mmsMediaPart.setAttachmentType(WorkingMessage.TEXT);
				}
				mediaParts.add(mmsMediaPart);
			});
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void showBitmap(final int width, final int height, final Bitmap bitmap) {
		runOnUiThread(() -> {
			bitmapList.add(bitmap);
			LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(width, height);
			layoutParams.bottomMargin = 10;
			layoutParams.gravity = Gravity.CENTER;
			FrameLayout frameLayout = new FrameLayout(MmsDetailActivity_2.this);
			frameLayout.setBackgroundResource(R.drawable.selector_item_bg_white_orange);
			frameLayout.setLayoutParams(layoutParams);
			frameLayout.setPadding(1,1,1,1);
			frameLayout.setFocusableInTouchMode(true);
			llMedia.addView(frameLayout);

			ImageView imageView = new ImageView(MmsDetailActivity_2.this);
			FrameLayout.LayoutParams ivParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
			imageView.setLayoutParams(ivParams);
			frameLayout.addView(imageView);
			imageView.setImageBitmap(bitmap);
			imageView.setBackgroundResource(R.color.white);
		});
	}

	private void showContent(final String content) {
		runOnUiThread(() -> {
			stringBuilder.append(content);
			TextView textView = new TextView(MmsDetailActivity_2.this);
			LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
			layoutParams.bottomMargin = 10;
			textView.setLayoutParams(layoutParams);
			textView.setTextAppearance(MmsDetailActivity_2.this, R.style.SubContentStyle);
			llMedia.addView(textView);
			textView.setText(content);
		});
	}

	private void showGif(final String id) {
		runOnUiThread(() -> {
			Uri partURI = Uri.parse("content://mms/part/" + id );
			try (InputStream is = getContentResolver().openInputStream(partURI)) {
				Movie movie = Movie.decodeStream(is);
				GifView gifView = new GifView(MmsDetailActivity_2.this);
				gifView.setPaused(false);
				gifView.setMovie(movie);
				int[] size = getBetterSize(movie.width(), movie.height());

				LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(size[0], size[1]);
				params.gravity = Gravity.CENTER;
				FrameLayout frameLayout = new FrameLayout(MmsDetailActivity_2.this);
				frameLayout.setBackgroundResource(R.drawable.selector_item_bg_white_orange);
				frameLayout.setLayoutParams(params);
				frameLayout.setPadding(1, 1, 1, 1);
				frameLayout.setFocusableInTouchMode(true);

				FrameLayout.LayoutParams gvParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
				gifView.setLayoutParams(gvParams);
				frameLayout.addView(gifView);
				gifView.setBackgroundResource(R.color.white);

				llMedia.addView(frameLayout);
			} catch (IOException e) {
				e.printStackTrace();
			}

		});

	}

	private void showVideoUi(final String _id, final Bitmap bitmap) {
		runOnUiThread(() -> {
			bitmapList.add(bitmap);
			FrameLayout frameLayout = new FrameLayout(MmsDetailActivity_2.this);
			LinearLayout.LayoutParams fParams;
			int padding = llMedia.getPaddingLeft() + llMedia.getPaddingRight();
			fParams = new LinearLayout.LayoutParams(screenWidth - padding, screenWidth / 3 * 2);
			fParams.gravity = Gravity.CENTER_HORIZONTAL;
			fParams.bottomMargin = 10;
			frameLayout.setBackgroundResource(R.drawable.selector_item_bg_balck_orange);
			frameLayout.setLayoutParams(fParams);
			frameLayout.setPadding(2,2,2,2);

			// 缩略图
			ImageView ivBg = new ImageView(MmsDetailActivity_2.this);
			FrameLayout.LayoutParams ibParams;
			ibParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
			if (bitmap == null) {
				ivBg.setBackgroundResource(android.R.color.background_dark);
			} else {
				ivBg.setBackground(new BitmapDrawable(getResources(), bitmap));
			}
			ibParams.gravity = Gravity.CENTER;
			ivBg.setLayoutParams(ibParams);
			ivBg.setScaleType(ImageView.ScaleType.CENTER_CROP);
			frameLayout.addView(ivBg);

			// 播放按钮
			ImageView imageView = new ImageView(MmsDetailActivity_2.this);
			FrameLayout.LayoutParams iParams = new FrameLayout.LayoutParams(60, 60);
			iParams.gravity = Gravity.CENTER;
			imageView.setLayoutParams(iParams);
			imageView.setImageResource(R.drawable.video_small);
			frameLayout.addView(imageView);

			llMedia.addView(frameLayout);
			frameLayout.setFocusableInTouchMode(true);
			frameLayout.setOnFocusChangeListener((view, b) -> {
				if (b) {
					videoRecognize = new MediaRecognize(_id, MediaRecognize.VIDEO);
				} else {
					videoRecognize = null;
				}
			});
		});
	}

	private void showAudioUi(String _id) {
		runOnUiThread(() -> {
			FrameLayout frameLayout = new FrameLayout(MmsDetailActivity_2.this);
			LinearLayout.LayoutParams fParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 50);
			fParams.bottomMargin = 10;
			frameLayout.setBackgroundResource(R.drawable.selector_audio_background);
			frameLayout.setLayoutParams(fParams);
			frameLayout.setPadding(10, 10, 10, 10);

			ImageView imageView = new ImageView(MmsDetailActivity_2.this);
			FrameLayout.LayoutParams iParams = new FrameLayout.LayoutParams(30, 30);
			iParams.gravity = Gravity.CENTER_VERTICAL;
			imageView.setLayoutParams(iParams);
			imageView.setImageDrawable(getResources().getDrawable(R.drawable.animation_paly_audio));
			frameLayout.addView(imageView);

			llMedia.addView(frameLayout);
			frameLayout.setFocusableInTouchMode(true);
			frameLayout.setOnFocusChangeListener(new OnAudioFocusChangedListener(_id, imageView));
		});
	}

	private class OnAudioFocusChangedListener implements View.OnFocusChangeListener {
		private final String _id;
		private final ImageView imageView;

		public OnAudioFocusChangedListener(String _id, ImageView imageView) {
			this._id = _id;
			this.imageView = imageView;
		}

		@Override
		public void onFocusChange(View view, boolean b) {
			if (b) {
				audioRecognize = new MediaRecognize(_id, MediaRecognize.AUDIO);
				audioAnimation = (AnimationDrawable) imageView.getDrawable();
			} else {
				stopAudio();
			}
		}
	}

	private Bitmap getMmsImage(String _id){ //读取图片附件
		Uri partURI = Uri.parse("content://mms/part/" + _id );
		InputStream is = null;
		Bitmap bitmap=null;
		try {
			is = getContentResolver().openInputStream(partURI);
			bitmap = BitmapFactory.decodeStream(is);
		}catch (IOException e) {
			e.printStackTrace();
			L.e("读取图片异常"+e.getMessage());
		}finally{
			if (is != null){
				try {
					is.close();
				}catch (IOException e){
					L.e("读取图片异常"+e.getMessage());
				}
			}
		}
		return bitmap;
	}

	private int[] getScreenSize() {
		DisplayMetrics outMetrics = new DisplayMetrics();
		getWindowManager().getDefaultDisplay().getRealMetrics(outMetrics);
		int widthPixel = outMetrics.widthPixels;
		int heightPixel = outMetrics.heightPixels;
		return new int[]{widthPixel, heightPixel};
	}

	private int[] getBetterSize(int oWidth, int oHeight) {
		int padding = llMedia.getPaddingLeft() + llMedia.getPaddingRight();
		if (screenWidth - padding >= oWidth) {
			return new int[]{oWidth, oHeight, 1};
		} else {
			int nHeight = screenWidth * oHeight / oWidth;
			int dw = screenWidth - padding;
			int dh = dw * nHeight / screenWidth;
			return new int[] {dw, dh, oWidth / screenWidth};
		}
	}



	@Override
	public void onDestroy() {
		super.onDestroy();
		for (Bitmap bitmap : bitmapList) {
			if (bitmap != null) {
				bitmap.recycle();
			}
		}
		if (imageBitmaps != null) {
			for (Bitmap bitmap : imageBitmaps) {
				if (bitmap != null)
					bitmap.recycle();
			}
		}
	}


	private void initVideo() {
		if (videoRecognize != null) {
			flMedia = new FrameLayout(MmsDetailActivity_2.this);
			flMedia.setBackgroundResource(android.R.color.background_dark);
			RelativeLayout.LayoutParams fParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
			fParams.addRule(RelativeLayout.ABOVE, R.id.layout_common_btm);
			flMedia.setLayoutParams(fParams);
			rlMmsDetail.addView(flMedia);

			videoView = new VideoView(MmsDetailActivity_2.this);
			Uri partURI = Uri.parse("content://mms/part/" + videoRecognize.getId());
			videoView.setVideoURI(partURI);
			FrameLayout.LayoutParams vParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
			vParams.gravity = Gravity.CENTER;
			videoView.setLayoutParams(vParams);
			flMedia.addView(videoView);
			videoView.setOnPreparedListener(mp -> {
				if (flMedia != null && videoView != null && !videoView.isPlaying()) {
					videoView.start();
					setBtmLeftString(R.string.txt_pause);
				}
			});
			videoView.setOnCompletionListener(mp -> {
				//视频播放完成后的回调
				if (flMedia != null && videoView != null && flMedia.isShown())
					setBtmLeftString(R.string.play);
			});
			videoView.setOnErrorListener((mp, what, extra) -> {
				//异常回调
				stopVideo();
				Toast.makeText(MmsDetailActivity_2.this, R.string.txt_video_format_error, Toast.LENGTH_SHORT).show();
				return false;//如果方法处理了错误,则为true;否则为false。返回false或根本没有OnErrorListener,将导致调用OnCompletionListener。
			});
		}
	}

	@Override
	public boolean onSoftLeftKeyEvent(KeyEvent event, boolean isActionUp) {
		if (isActionUp) {
			if (!handleVideo() && !handleAudio()){
				showMenu(MENU_NORMAL);
			}
		}
		return true;
	}

	private boolean handleAudio() {
		if (audioPlayer != null) {
			if (audioPlayer.isPlaying()) {
				if (audioAnimation != null)
					audioAnimation.stop();
				audioPlayer.pause();
				setBtmLeftString(R.string.play);
			} else {
				if (audioAnimation != null)
					audioAnimation.start();
				audioPlayer.start();
				setBtmLeftString(R.string.txt_pause);
			}
			return true;
		} else if (audioRecognize != null) {
			showMenu(MENU_WITH_MEDIA);
			return true;
		}
		return false;
	}

	private boolean handleVideo() {
		if (flMedia != null && videoView != null) {
			if (videoView.isPlaying()) {
				videoView.pause();
				setBtmLeftString(R.string.play);
			} else {
				videoView.start();
				setBtmLeftString(R.string.txt_pause);
			}
			return true;
		} else if (videoRecognize != null){
			showMenu(MENU_WITH_MEDIA);
			return true;
		}
		return false;
	}

	@Override
	protected void onMenuSelect(String selectString, int position) {
		if (selectString.equals(getString(R.string.play))) {
			initVideo();
			initAudio();
		} else if (selectString.equals(getString(R.string.replay_sms)) || selectString.equals(getString(R.string.sned_sms))) {
			SmsTools.sendNewSms(this, selectString.equals(getString(R.string.replay_sms)) ? 2 : 1,
					selectString.equals(getString(R.string.replay_sms)) ? mmsBean.getPhone() : "");
		} else if (selectString.equals(getString(R.string.forward_sms))) {
			forwardMms();
		} else if (selectString.equals(getString(R.string.make_call))) {
			Utils.makeCall(this, mmsBean.getPhone());
		} else if (selectString.equals(getString(R.string.delete))) {
			MmsDao.getInstance().deleteOneData(this, mmsBean.getId());
			finish();
		}
	}

	private void forwardMms() {
		etTo.setShowPop(false);
		etTo.setDelKey(KeyEvent.KEYCODE_ENTER);
		etTo.addTextChangedListener(new TextWatcher() {
			@Override
			public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

			}

			@Override
			public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {

			}

			@Override
			public void afterTextChanged(Editable editable) {
				if (etTo.isFocused()) {
					if (editable.toString().endsWith("; ")) {
						refreshBottomTip(true);
						if (mPopup != null && mPopup.isShowing()) {
							mPopup.dismiss();
						}
						return;
					}
					if (filterTask != null && filterTask.getStatus() == AsyncTask.Status.RUNNING) {
						filterTask.cancel(true);
						filterTask = null;
					}
					filterTask = new FilterTask();
					String find = "";
					if (MM.isMfs(MM.MF_TWNSCT)) {
						find = editable.toString();
					} else {
						if (editable.toString().contains("; ")) {
							find = editable.toString().substring(editable.toString().lastIndexOf("; ") + 2);
						} else {
							find = editable.toString();
						}
					}
					filterTask.execute(find);
				}
			}
		});
		etTo.setText("");
		etTo.requestFocus();
		etTo.setSelection(0);
		if (!MM.isMfs(MM.MF_TWNSCT)) {
			etTo.setSingleLine(false);
			etTo.setMaxLines(20);
		}
		etTo.setInputStatusChangeLinster(new MyEditTextView.InputStatusChangeLinster() {
			@Override
			public void onInputTypeChangeed(MyEditTextView editTextView, String type) {
				setBtmCenterString(type);
			}

			@Override
			public void onDeleteableChangeed(boolean canDelete) {
				if (canDelete) {
					setBtmLeftString(R.string.delete);
					setBtmRightString(R.string.select);
				} else {
					setBtmLeftString(R.string.empty_string);
					setBtmRightString(R.string.back);
				}

			}
		});
		if (!MM.isMfs(MM.MF_TWNSCT)) {
			etTo.setOnKeyListener((v, keyCode, event) -> {
				if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT || keyCode == KeyEvent.KEYCODE_DPAD_UP) {
					return true;
				}
				if ((keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_OK || keyCode == KeyEvent.KEYCODE_DPAD_CENTER)
						&& ((mPopup != null && (!mPopup.isShowing() || mPopup.getSelectedItemPosition() == -1)) || fromType != 0)) {
					if (etTo.length() > 0 && event.getAction() == KeyEvent.ACTION_UP) {
						String string = etTo.getText().toString();
						if (string.endsWith("; ")) {
							etTo.setText(string.subSequence(0, string.length() - 2));
						} else {
							etTo.setText(string.subSequence(0, string.length() - 1));
						}
						etTo.setSelection(etTo.length());
					}
					return true;
				} else if (keyCode >= KeyEvent.KEYCODE_0 && keyCode <= KeyEvent.KEYCODE_9) {
					String[] rs = etTo.getText().toString().split("; ");
					if (rs != null && rs.length > 100) {
						T.makeToast(getString(R.string.new_message_contacts_limit, 100));
						return true;
					}
				} else if (keyCode == KeyEvent.KEYCODE_STAR) {
					if (!event.isDown()) {
						etTo.getText().append("+");
						etTo.setSelection(etTo.length());
					}
					return true;
				}
				return etTo.onKey(v, keyCode, event);
			});
		}
		etTo.setOnFocusChangeListener((view, b) -> {
			if (!b) {
				if (mPopup != null && mPopup.isShowing()) {
					mPopup.dismiss();
					refreshBottomTip(true);
				}
			}
		});
		rlInputRecipient.setVisibility(View.VISIBLE);
		tips.setVisibility(View.VISIBLE);
		if (TextUtils.isEmpty(etTo.getText()))
			setBtmLeftString(R.string.empty_string);
		else 
			setBtmLeftString(R.string.delete);
	}
	
//	private final MyEditTextView.InputStatusChangeLinster inputStatusChangeLinster = ;

//	private final View.OnKeyListener onKeyListener =;

	private void initAudio() {
		if (audioRecognize != null) {
			audioPlayer = new MediaPlayer();
			try {
				Uri uri = Uri.parse("content://mms/part/" + audioRecognize.getId());
				audioPlayer.setDataSource(this, uri);
				audioPlayer.prepare();
				setBtmLeftString(R.string.txt_pause);
				audioPlayer.setOnCompletionListener(mediaPlayer -> {
					if (audioAnimation != null) {
						audioAnimation.stop();
					}
					setBtmLeftString(R.string.play);
				});
				audioPlayer.setOnErrorListener((mediaPlayer, i, i1) -> {
					Toast.makeText(MmsDetailActivity_2.this, R.string.txt_audio_format_error, Toast.LENGTH_SHORT).show();
					stopAudio();
					return false;
				});
				audioPlayer.start();
				if (audioAnimation != null)
					audioAnimation.start();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	@Override
	public boolean onSoftRightKeyEvent(KeyEvent event, boolean isActionUp) {
		if (isActionUp) {
			if (rlInputRecipient.isShown()) {
				stopSendMms();
			} else if (flMedia != null && flMedia.isShown()) {
				stopVideo();
				return true;
			} else if (audioPlayer != null){
				stopAudio();
				return true;
			}

		}
		return super.onSoftRightKeyEvent(event, isActionUp);
	}

	private void stopSendMms() {
//		etTo.setText("");
//		isExcuteCancel = true;
		rlInputRecipient.setVisibility(View.GONE);
		tips.setVisibility(View.GONE);
		etTo.addTextChangedListener(null);
		etTo.setOnFocusChangeListener(null);
		etTo.setInputStatusChangeLinster(null);
		etTo.setOnKeyListener(null);
		filterTask.cancel(true);
//		isExcuting = false;
//		rlInputRecipient = null;
//		tips = null;
//		etTo = null;
		if (mPopup != null) mPopup.dismiss();
		setBtmLeftString(R.string.menu);
	}

	private void stopVideo() {
		flMedia.setVisibility(View.GONE);
		if (videoView != null) {
			videoView.setOnPreparedListener(null);
			videoView.setOnCompletionListener(null);
			videoView.setOnErrorListener(null);
			videoView.stopPlayback();
			videoView = null;
		}
		flMedia = null;
		setBtmLeftString(R.string.menu);
	}

	private void stopAudio() {
		if (audioAnimation != null) {
			audioAnimation.stop();
		}
		if (audioPlayer != null) {
			audioPlayer.stop();
			audioPlayer.setOnErrorListener(null);
			audioPlayer.setOnCompletionListener(null);

		}
		audioAnimation = null;
		audioPlayer = null;
		audioRecognize = null;
		setBtmLeftString(R.string.menu);
	}

	private void numberPast() {
		//show number if from calllog
		if (getIntent().getData() != null) {
			String phoneNumber = getIntent().getData().toString();
			phoneNumber = phoneNumber.substring(6) + "; ";
			etTo.setText(phoneNumber);
			if (mPopup != null && mPopup.isShowing()) {
				refreshBottomTip(true);
				mPopup.dismiss();
			}
		}
	}

	public void refreshBottomTip(boolean isSendMessage) {
		tips.setText(isSendMessage ? R.string.hint_send_message : R.string.hint_select);
	}

	private void initContact() {
		CustomThreadPool.get().execute(() -> {
			Cursor contactCursor = getContentResolver().query(
					ContactsContract.RawContactsEntity.CONTENT_URI,
					new String[]{ContactsContract.RawContactsEntity.CONTACT_ID, ContactsContract.RawContactsEntity.MIMETYPE,
							ContactsContract.RawContactsEntity.DATA1, ContactsContract.RawContactsEntity.DATA2, "account_type"},
					"deleted=0", null, "contact_id ASC");
			// String printCursor = Utils.printCursor(contactCursor);
			// contactCursor.moveToFirst();
			while (contactCursor.moveToNext()) {
				String idString = contactCursor.getString(0);
				String mimeTypeString = contactCursor.getString(1);
				String data1String = contactCursor.getString(2);
				String data2String = contactCursor.getString(3);
				String accountTypeString = contactCursor.getString(4);
				if (contactBeans.size() == 0
						|| !TextUtils.equals(contactBeans.get(contactBeans.size() - 1).id, idString)) {
					contactBeans.add(new ContactBean());
				}
				if (TextUtils.isEmpty(contactBeans.get(contactBeans.size() - 1).id)) {
					contactBeans.get(contactBeans.size() - 1).id = idString;
					contactBeans.get(contactBeans.size() - 1).isFromSimCard = !TextUtils
							.equals("Local Phone Account", accountTypeString);
				}
				if (TextUtils.equals(mimeTypeString, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)) {
					contactBeans.get(contactBeans.size() - 1).name = data1String;
				} else if (TextUtils.equals(mimeTypeString, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)) {
					if ("1".equals(data2String) || "2".equals(data2String)) {
						contactBeans.get(contactBeans.size() - 1).mobileCallNum = data1String;
					} else if ("3".equals(data2String)) {
						contactBeans.get(contactBeans.size() - 1).officeCallNum = data1String;
					} else if ("7".equals(data2String)) {
						contactBeans.get(contactBeans.size() - 1).otherCallNum = data1String;
					}
				}
			}
			contactCursor.close();

		});
	}

	private static class ContactBean {
		private String id = "", name = "", officeCallNum = "", mobileCallNum = "", otherCallNum = "", simIndex = "";
		private boolean isFromSimCard;

		@Override
		public String toString() {
			return name + "," + officeCallNum + "," + mobileCallNum + "," + otherCallNum + ",";
		}
	}

	@Override
	public boolean onOkKeyEvent(KeyEvent event, boolean isActionUp) {
		if (isActionUp) {
			if (rlInputRecipient.isShown()) {
				String phoneNums = etTo.getText().toString().trim();
				String[] recivers = phoneNums.split(";");
				if (recivers.length > 0) {
					forwardMms(recivers);
				}
			}
		}
		return super.onOkKeyEvent(event, isActionUp);
	}

	private void forwardMms(String[] recivers) {
		/*Toast.makeText(this, R.string.chat_setting_sending, Toast.LENGTH_SHORT).show();
		CustomThreadPool.get().execute(() -> {
			String subject = TextUtils.isEmpty(mmsBean.getSubject()) ? getString(R.string.forward_sms) : mmsBean.getSubject();
			SmsTools.sendMms(MmsDetailActivity_2.this, stringBuilder.toString(), recivers, subject,
					mmsBean.getThreadId(), audios, videos, gifs, imageBitmaps);
		});
		stopSendMms();
		finish();
		Intent intent = getIntent();
		intent.setClass(this, MmsDetailActivity_2.class);
		startActivity(intent);*/
//		Uri uri = Uri.parse("content://mms/inbox/" + mmsBean.getId());
//		List<String> numbers = Arrays.asList(recivers);
//		String subject = TextUtils.isEmpty(mmsBean.getSubject()) ? getString(R.string.forward_sms) : mmsBean.getSubject();
//		SmsTools.sendMmsBySystem(this, uri, mmsBean.getThreadId(), numbers, mmsBean.getPartContent(), subject, mediaParts,
//						numbers.size() > 0, true, messageStatusListener);
		try {
//			Log.v("Sage Test", "彩信发送中");
			Toast.makeText(this, R.string.ipmsg_send_exception, Toast.LENGTH_SHORT).show();
			MmsTools.send(this, recivers[0], TextUtils.isEmpty(mmsBean.getSubject()) ? getString(R.string.forward_sms) : mmsBean.getSubject(),
					mmsBean.getId());
			stopSendMms();
			finish();
			Intent intent = getIntent();
			intent.setClass(this, MmsDetailActivity_2.class);
			startActivity(intent);
		} catch (Exception e) {
			e.printStackTrace();
		}

	}
	
//	private final TextWatcher textWatcher = ;

	@SuppressLint("StaticFieldLeak")
	private class FilterTask extends AsyncTask<String, Void, ArrayList<ContactBean>> {
		@Override
		protected void onPreExecute() {
			super.onPreExecute();
//			isExcuting = true;
		}

		@Override
		protected ArrayList<ContactBean> doInBackground(String... params) {
			ArrayList<ContactBean> contactBeen = new ArrayList<ContactBean>();
			String tag = params[0];
			if (!MM.isMfs(MM.MF_TWNSCT)) {
				boolean hasChar = false;
				for (int i = 0; i < tag.length(); i++) {
					char charAt = tag.charAt(i);
					if (!(charAt >= '0' && charAt <= '9') && charAt != '+') {
						hasChar = true;
						break;
					}
				}
				if (!hasChar) {
					ContactBean cb1 = new ContactBean();
					cb1.name = tag;
					cb1.mobileCallNum = tag;
					contactBeen.add(cb1);
				}
			}
			for (ContactBean contactBean : contactBeans) {
				if (contactBean.name.toLowerCase().contains(tag.toLowerCase())) {
					if (!TextUtils.isEmpty(contactBean.mobileCallNum)) {
						ContactBean cb1 = new ContactBean();
						cb1.name = contactBean.name;
						cb1.mobileCallNum = contactBean.mobileCallNum;
						contactBeen.add(cb1);
					}

					if (!TextUtils.isEmpty(contactBean.officeCallNum)) {
						ContactBean cb2 = new ContactBean();
						cb2.name = contactBean.name;
						cb2.mobileCallNum = contactBean.officeCallNum;
						contactBeen.add(cb2);
					}

					if (!TextUtils.isEmpty(contactBean.otherCallNum)) {
						ContactBean cb3 = new ContactBean();
						cb3.name = contactBean.name;
						cb3.mobileCallNum = contactBean.otherCallNum;
						contactBeen.add(cb3);
					}
				} else {
					if (contactBean.mobileCallNum.contains(tag)) {
						ContactBean cb1 = new ContactBean();
						cb1.name = contactBean.name;
						cb1.mobileCallNum = contactBean.mobileCallNum;
						contactBeen.add(cb1);
					}
					if (contactBean.officeCallNum.contains(tag)) {
						ContactBean cb2 = new ContactBean();
						cb2.name = contactBean.name;
						cb2.mobileCallNum = contactBean.officeCallNum;
						contactBeen.add(cb2);
					}
					if (contactBean.otherCallNum.contains(tag)) {
						ContactBean cb3 = new ContactBean();
						cb3.name = contactBean.name;
						cb3.mobileCallNum = contactBean.otherCallNum;
						contactBeen.add(cb3);
					}
				}
			}
			return contactBeen;
		}

		@Override
		protected void onPostExecute(ArrayList<ContactBean> result) {
			initListPopuwindow();
			if (result.size() == 0) {
				ContactBean contactBean = new ContactBean();
				contactBean.id = "-1";
				contactBean.name = getString(R.string.input_sms_um_error_tips);
				result.add(contactBean);
			}
			adapter.setContactBeans(result);
			if (result.size() > 3) {
				mPopup.setHeight(AppUtils.screenH / 2 - 7);
			} else {
				mPopup.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
			}
			refreshBottomTip(false);
			mPopup.show();
			mPopup.getListView().setDivider(getDrawable(R.drawable.bg_divider_horizontal));
		}
	}

	private class MyAdapter extends BaseAdapter {
		ArrayList<ContactBean> contactBeans;

		public MyAdapter(ArrayList<ContactBean> contactBeans) {
			this.contactBeans = contactBeans;
		}

		public void setContactBeans(ArrayList<ContactBean> contactBeans) {
			this.contactBeans = contactBeans;
			notifyDataSetChanged();
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			if (convertView == null) {
				convertView = LayoutInflater.from(MmsDetailActivity_2.this).inflate(R.layout.simple_expandable_list_item_2,
						null);
			}
			TextView tv1 = ((TextView) convertView.findViewById(android.R.id.text1));
			TextView tv2 = (TextView) convertView.findViewById(android.R.id.text2);
			if (position == 0 && !MM.isMfs(MM.MF_TWNSCT)) {
				tv2.setVisibility(View.GONE);
			} else {
				tv2.setVisibility(View.VISIBLE);
			}
			tv1.setText(getItem(position).name);
			tv2.setText(getItem(position).mobileCallNum);
			return convertView;
		}

		@Override
		public long getItemId(int position) {
			return position;
		}

		@Override
		public ContactBean getItem(int position) {
			return this.contactBeans.get(position);
		}

		@Override
		public int getCount() {
			return this.contactBeans.size();
		}
	}

	public void initListPopuwindow() {
		if (mPopup == null) {
			mPopup = new ListPopupWindow(this);
			mPopup.setAdapter(adapter);
			mPopup.setOnItemClickListener(contactItemClickListener);
			mPopup.setAnchorView(etTo);
			mPopup.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
			mPopup.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
			mPopup.setForceIgnoreOutsideTouch(true);
		}
	}
	
	private final AdapterView.OnItemClickListener contactItemClickListener = new AdapterView.OnItemClickListener() {

		@Override
		public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
//			if (isExcuteCancel) return;
			String mobileCallNum = ((ContactBean) mPopup.getListView().getSelectedItem()).mobileCallNum.replace(" ", "");
			String ts = mobileCallNum;
			if (!MM.isMfs(MM.MF_TWNSCT)) {
				String textstring = etTo.getText().toString();
				if (textstring.contains("; ") && (textstring.startsWith(mobileCallNum + "; ") || textstring.contains("; " + mobileCallNum + "; "))) {
					T.makeToast(R.string.duplicated_recipient);
//                isSelected = false;
					ts = textstring.substring(0, textstring.lastIndexOf("; ")) + "; ";
					etTo.setText(ts);
					etTo.setSelection(etTo.length());
					return;
				}
				if (textstring.contains("; ")) {
					ts = textstring
							+ mobileCallNum.substring(textstring.substring(textstring.lastIndexOf("; ") + 2).length());
					ts = textstring.substring(0, textstring.lastIndexOf("; ")) + "; " + mobileCallNum;
				}
				ts += "; ";
			}
			etTo.setText(ts);
			etTo.setSelection(etTo.length());
		}
	};

	@Override
	public boolean dispatchKeyEvent(int keyCode, boolean isActionUp, KeyEvent event) {
		if (mPopup != null && mPopup.isShowing()) {
			if (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_DOWN || event.getKeyCode() == KeyEvent.KEYCODE_DPAD_UP || event.getKeyCode() == KeyEvent.KEYCODE_DPAD_CENTER
					|| event.getKeyCode() == KeyEvent.KEYCODE_BACK || event.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
				// if (event.getAction() == KeyEvent.ACTION_UP) {
				switch (event.getKeyCode()) {
					case KeyEvent.KEYCODE_DPAD_DOWN:
						if (event.getAction() == KeyEvent.ACTION_UP)
							mPopup.setSelection(mPopup.getSelectedItemPosition() + 1);
						break;
					case KeyEvent.KEYCODE_DPAD_UP:
						if (event.getAction() == KeyEvent.ACTION_UP)
							mPopup.setSelection(mPopup.getSelectedItemPosition() - 1);
						break;
					case KeyEvent.KEYCODE_BACK:
						if (event.getAction() == KeyEvent.ACTION_UP) {
							if (etTo.getText().length() == 0) {
								backUI();
								return true;
							}
							selectInputItem();
						}
						return true;
					case KeyEvent.KEYCODE_DPAD_CENTER:
						if (event.getAction() == KeyEvent.ACTION_UP) {
							selectInputItem();
						}
						break;
					case KeyEvent.KEYCODE_ENTER:
						etTo.dispatchKeyEvent(event);
						break;

					case KeyEvent.KEYCODE_M:
						if (isActionUp)
							backUI();
						return true;

					default:
						break;
				}
				// }
				return true;
			}
		}
		if (rlInputRecipient.isShown() && keyCode == KeyEvent.KEYCODE_M) {
			if (isActionUp)
				backUI();
			return true;
		}
		return super.dispatchKeyEvent(keyCode, isActionUp, event);
	}

	private void backUI() {
		stopSendMms();
		finish();
		Intent intent = getIntent();
		intent.setClass(this, MmsDetailActivity_2.class);
		startActivity(intent);
	}

	private void selectInputItem() {
		if (adapter.getCount() == 0) {
			return;
		}
		int p = mPopup.getSelectedItemPosition();
		if (p == -1) {
			p = 0;
		}
		mPopup.setSelection(p);
		ContactBean selectedItem = (ContactBean) mPopup.getListView().getSelectedItem();
		if (TextUtils.equals("-1", selectedItem.id)) {//id为-1时,联系人输入错误
			T.makeToast(R.string.input_sms_um_error_tips);
			return;
		} else {
			if (!TextUtils.isEmpty(selectedItem.mobileCallNum)) {//处理输入+号的情况
				if (TextUtils.equals("+", selectedItem.mobileCallNum)) {
					T.makeToast(R.string.input_sms_um_error_tips);
					return;
				} else {
					if (selectedItem.mobileCallNum.contains("+") && selectedItem.mobileCallNum.lastIndexOf("+") != 0) {
						T.makeToast(R.string.input_sms_um_error_tips);
						return;
					}
				}
			}
		}

		contactItemClickListener.onItemClick(null, null, p, 0);

		refreshBottomTip(true);
		mPopup.dismiss();
	}

	private final WorkingMessage.MessageStatusListener messageStatusListener = new WorkingMessage.MessageStatusListener(){
		private final static String TAG = "Sage Test";

		@Override
		public void onProtocolChanged(boolean isMms, boolean needToast) {
			Log.v(TAG, "== onProtocolChanged == isMms = " + isMms);
		}

		@Override
		public void onAttachmentChanged() {
			Log.v(TAG, "== onAttachmentChanged ==");
		}

		@Override
		public void onPreMessageSent() {
			Log.v(TAG, "== onPreMessageSent ==");
			handler.sendEmptyMessage(PRE_MESSAGE_SENT);
		}

		@Override
		public void onMessageSent() {
			Log.v(TAG, "== onMessageSent ==");
			handler.sendEmptyMessage(MESSAGE_SENT);
		}

		@Override
		public void onMaxPendingMessagesReached() { // 信息队列太多,不允许发送
			Log.v(TAG, "== onMaxPendingMessagesReached ==");
			handler.sendEmptyMessage(PENDING_MESSAGES_REACHED);
		}

		@Override
		public void onAttachmentError(int error) {
			Log.v(TAG, "== onAttachmentError ==");
			handler.sendEmptyMessage(ATTACHMENT_ERROR);
		}

		@Override
		public void onPreMmsSent() {
			Log.v(TAG, "== onPreMmsSent ==");
			handler.sendEmptyMessage(PRE_MMS_SENT);
		}
	};

	private void restartThis() {
		stopSendMms();
		Intent intent = getIntent();
		intent.setClass(this, MmsDetailActivity_2.class);
		startActivity(intent);
	}

	@SuppressLint("HandlerLeak")
	private final Handler handler = new Handler() {

		@Override
		public void handleMessage(Message message) {
			super.handleMessage(message);
			switch (message.what) {
				case PRE_MESSAGE_SENT:
					Utils.showProgressDialog(MmsDetailActivity_2.this, R.string.sending_message);
					break;
				case MESSAGE_SENT:
					Utils.dismissProgressDialog();
					Toast.makeText(MmsDetailActivity_2.this, R.string.strOk, Toast.LENGTH_SHORT).show();
					restartThis();
					break;
				case PENDING_MESSAGES_REACHED:

					break;
				case ATTACHMENT_ERROR:
					Utils.dismissProgressDialog();
//					Toast.makeText(MmsDetailActivity_2.this, R.string.ipmsg_send_exception, Toast.LENGTH_SHORT).show();
					restartThis();
					break;
				case PRE_MMS_SENT:

					break;

			}
		}
	};
}

在使用MmsTools之前可能要添加
android {

useLibrary ‘org.apache.http.legacy’
}

package 发送彩信工具类;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.net.http.AndroidHttpClient;
import android.provider.Telephony;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

import com.android.mms.R;
import com.android.mms.model.SlideshowModel;
import com.google.android.mms.MmsException;
import com.google.android.mms.pdu.CharacterSets;
import com.google.android.mms.pdu.EncodedStringValue;
import com.google.android.mms.pdu.PduBody;
import com.google.android.mms.pdu.PduComposer;
import com.google.android.mms.pdu.PduPart;
import com.google.android.mms.pdu.SendReq;
import com.vogtec.sms.MmsListActivity;

import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.params.ConnRouteParams;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;

/**
 * Create by Sage Luo
 * on 2020/12/23 0023 09:17
 */
public class MmsTools {
	private final static String TAG = "Sage Test";
	// 电信彩信中心url,代理,端口
//	彩信中心URL:mmsc.vnet.mobi
//  WAP网关IP地址:10.0.0.200
	public static String mmscUrl_ct = "http://mmsc.vnet.mobi";
	public static String mmsProxy_ct = "10.0.0.200";
	// 移动彩信中心url,代理,端口
//	⑧MMSC:mmsc.monternet.com
//  ⑨彩信代理:010.000.000.172
	public static String mmscUrl_cm = "http://mmsc.monternet.com";
	public static String mmsProxy_cm = "010.000.000.172";
	// 联通彩信中心url,代理,端口
//	8 MMSC:mmsc.myuni.com.cn
//  9 彩信代理:010.000.000.172
//	public static String mmscUrl_uni = "http://mmsc.vnet.mobi";
//	public static String mmsProxy_uni = "10.0.0.172";
	public static String mmscUrl_uni = "http://mmsc.myuni.com.cn";
	public static String mmsProxy_uni = "010.000.000.172";

	private static List<String> getSimMNC(Context context){
		TelephonyManager telManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
		String imsi = telManager.getSubscriberId();
		Log.i(TAG, "imsi = " + imsi);
		if(imsi!=null){
			ArrayList<String> list = new ArrayList<>();
			if(imsi.startsWith("46000") || imsi.startsWith("46002") || imsi.startsWith("46007")){
				//因为移动网络编号46000下的IMSI已经用完,所以虚拟了一个46002编号,134/159号段使用了此编号
				//中国移动
				list.add(mmscUrl_cm);
				list.add(mmsProxy_cm);
			}else if(imsi.startsWith("46001")){
				//中国联通
				list.add(mmscUrl_uni);
				list.add(mmsProxy_uni);
			}else if(imsi.startsWith("46003")){
				//中国电信
				list.add(mmscUrl_ct);
				list.add(mmsProxy_ct);
			}
			shouldChangeApn(context);
			return list;
		}
		return null;
	}

	/**
	 * 当当前的apn接入点不是发彩信所需要的wap时,就需要切换:
	 */
	private static boolean shouldChangeApn(final Context context){

		final String wapId = getWapApnId(context);
		String apnId = getApn(context);
		//若当前apn不是wap,则切换至wap
		if(!wapId.equals(apnId)){
			APN_NET_ID = apnId;
			setApn(context,wapId);
			//切换apn需要一定时间,先让等待2秒
			try {
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			return true;
		}
		return false;
	}

	private static String getApn(Context context){
		ContentResolver resoler = context.getContentResolver();
		String[] projection = new String[]{"_id"};
		Cursor cur = resoler.query(Uri.parse("content://telephony/carriers/preferapn"),projection, null, null, null);
		String apnId = null;
		if(cur!=null&&cur.moveToFirst()){
			do {
				apnId = cur.getString(cur.getColumnIndex("_id"));
			} while (cur.moveToNext());
		}
		return apnId;
	}
	/**
	 * 设置接入点
	 * @param id
	 */
	private static void setApn(Context context ,String id){
		Uri uri = Uri.parse("content://telephony/carriers/preferapn");
		ContentResolver resolver = context.getContentResolver();
		ContentValues values = new ContentValues();
		values.put("apn_id", id);
		resolver.update(uri, values, null, null);
	}
	private static String APN_NET_ID = null;
	/**
	 * 取到wap接入點的id
	 * @return
	 */
	private static String getWapApnId(Context context){
		ContentResolver contentResolver = context.getContentResolver();
		String[] projection = new String[]{"_id","proxy"};
		Cursor cur = contentResolver.query(Uri.parse("content://telephony/carriers"), projection, "current = 1", null, null);
		if(cur!=null&&cur.moveToFirst()){
			do {
				String id = cur.getString(0);
				String proxy = cur.getString(1);
				if(!TextUtils.isEmpty(proxy)){
					return id;
				}
			} while (cur.moveToNext());
		}
		return null;
	}

	private static boolean sendMMMS(List<String> list, final Activity activity, byte[] pdu) throws Exception {
		// HDR_AVLUE_ACCEPT_LANGUAGE = getHttpAcceptLanguage();
		if(list==null){
			activity.runOnUiThread(() -> {
				Toast.makeText(activity, R.string.ipmsg_getsim_failed, Toast.LENGTH_LONG).show();
			});
			return false;
		}
		String mmsUrl = (String) list.get(0);
		String mmsProxy = (String) list.get(1);
		HttpClient client = null;
		try {
			URI hostUrl = new URI(mmsUrl);
			HttpHost target = new HttpHost(hostUrl.getHost(),
					hostUrl.getPort(), HttpHost.DEFAULT_SCHEME_NAME);
			client = AndroidHttpClient.newInstance("Android-Mms/2.0");
			HttpPost post = new HttpPost(mmsUrl);
			ByteArrayEntity entity = new ByteArrayEntity(pdu);
			entity.setContentType("application/vnd.wap.mms-message");
			post.setEntity(entity);
			post.addHeader(HDR_KEY_ACCEPT, HDR_VALUE_ACCEPT);
			post.addHeader(HDR_KEY_ACCEPT_LANGUAGE, HDR_VALUE_ACCEPT_LANGUAGE);

			HttpParams params = client.getParams();
			HttpProtocolParams.setContentCharset(params, "UTF-8");

			ConnRouteParams.setDefaultProxy(params, new HttpHost(mmsProxy,
					80));
			HttpResponse response = client.execute(target, post);
			StatusLine status = response.getStatusLine();
			System.out.println("status : " + status.getStatusCode());
			if (status.getStatusCode() != 200) {
				throw new IOException("HTTP error: " + status.getReasonPhrase());
			}
			//彩信发送完毕后检查是否需要把接入点切换回来
			if(null!=APN_NET_ID){
				setApn(activity, APN_NET_ID);
			}
			return true;

		} catch (Exception e) {
			e.printStackTrace();
//			Log.d(TAG, "彩信发送失败:"+e.getMessage());
			//发送失败处理
		}
		return false;
	}

//	private static boolean sendMMMS(List<String> list, final Activity activity, byte[] pdu) throws Exception {
		 HDR_AVLUE_ACCEPT_LANGUAGE = getHttpAcceptLanguage();
//		if(list==null){
//			activity.runOnUiThread(() -> {
//				Toast.makeText(activity, "找不到sim卡", Toast.LENGTH_LONG).show();
//			});
//			return false;
//		}
//		String mmsUrl = (String) list.get(0);
//		String mmsProxy = (String) list.get(1);
//		return false;
//	}

	private static String HDR_VALUE_ACCEPT_LANGUAGE = "";
	private static final String HDR_KEY_ACCEPT = "Accept";
	private static final String HDR_KEY_ACCEPT_LANGUAGE = "Accept-Language";
	private static final String HDR_VALUE_ACCEPT = "*/*, application/vnd.wap.mms-message, application/vnd.wap.sic";
	/**
	 * 发彩信接口 by liuhanzhi
	 * @param activity
	 * @param phone 手机号
	 * @param subject 主题
	 * @param text	文字
	 * @param imagePath 图片路径
	 * @param audioPath	音频路径
	 */
	public static void send(final Activity activity, String phone,String subject,String text,String imagePath,String audioPath) {
//		String subject = "测试彩信";
		Log.v("Sage Test", subject);
//		String recipient = "18911722352";// 138xxxxxxx
		SendReq sendRequest = new SendReq();
		EncodedStringValue[] sub = EncodedStringValue.extract(subject);
		if (sub != null && sub.length > 0) {
			sendRequest.setSubject(sub[0]);
		}
		EncodedStringValue[] phoneNumbers = EncodedStringValue
				.extract(phone);
		if (phoneNumbers != null && phoneNumbers.length > 0) {
			sendRequest.addTo(phoneNumbers[0]);
		}
		PduBody pduBody = new PduBody();
		if(!TextUtils.isEmpty(text)){
			PduPart partPdu3 = new PduPart();
			partPdu3.setCharset(CharacterSets.UTF_8);
			partPdu3.setName("mms_text.txt".getBytes());
			partPdu3.setContentType("text/plain".getBytes());
			partPdu3.setData(text.getBytes());
			pduBody.addPart(partPdu3);
		}
		if(!TextUtils.isEmpty(imagePath)){
			PduPart partPdu = new PduPart();
			partPdu.setCharset(CharacterSets.UTF_8);
			partPdu.setName("camera.jpg".getBytes());
			partPdu.setContentType("image/png".getBytes());
//		partPdu.setDataUri(Uri.parse("file://mnt//sdcard//.lv//photo//1326858009625.jpg"));
			partPdu.setDataUri(Uri.fromFile(new File(imagePath)));
			pduBody.addPart(partPdu);
		}
		if(!TextUtils.isEmpty(audioPath)){
			PduPart partPdu2 = new PduPart();
			partPdu2.setCharset(CharacterSets.UTF_8);
			partPdu2.setName("speech_test.amr".getBytes());
			partPdu2.setContentType("audio/amr".getBytes());
			// partPdu2.setContentType("audio/amr-wb".getBytes());
//			partPdu2.setDataUri(Uri.parse("file://mnt//sdcard//.lv//audio//1326786209801.amr"));
			partPdu2.setDataUri(Uri.fromFile(new File(audioPath)));
			pduBody.addPart(partPdu2);
		}

		sendRequest.setBody(pduBody);
		final PduComposer composer = new PduComposer(activity, sendRequest);
		final byte[] bytesToSend = composer.make();
		final List<String> list = getSimMNC(activity);
		Thread t = new Thread(new Runnable() {
			@Override
			public void run() {
				//因为在切换apn过程中需要一定时间,所以需要加上一个重试操作
				int retry = 0;
				do {
//					Log.d(TAG, "重试次数:"+(retry+1));
					try {
						if (sendMMMS(list, activity, bytesToSend)) {
							activity.runOnUiThread(()->{
								Toast.makeText(activity, R.string.strOk,
										Toast.LENGTH_LONG).show();
							});
							return;
						}
						retry++;
						Thread.sleep(2000);
					} catch (Exception e) {
						e.printStackTrace();
					}
				} while (retry < 5);
				activity.runOnUiThread(() -> {
					Toast.makeText(activity, R.string.strFail, Toast.LENGTH_LONG).show();
				});
			}
		});
		t.start();
	}

	public static void send(final Activity activity, String phone,String subject, long id) throws MmsException {
//		String subject = "测试彩信";
		Log.v("Sage Test", subject);
//		String recipient = "18911722352";// 138xxxxxxx
		SendReq sendRequest = new SendReq();
		EncodedStringValue[] sub = EncodedStringValue.extract(subject);
		if (sub != null && sub.length > 0) {
			sendRequest.setSubject(sub[0]);
		}
		EncodedStringValue[] phoneNumbers = EncodedStringValue
				.extract(phone);
		if (phoneNumbers != null && phoneNumbers.length > 0) {
			sendRequest.addTo(phoneNumbers[0]);
		}
		PduBody pduBody = SlideshowModel.getPduBody(activity, ContentUris.withAppendedId(Telephony.Mms.Inbox.CONTENT_URI, id));
		sendRequest.setBody(pduBody);

		final PduComposer composer = new PduComposer(activity, sendRequest);
		final byte[] bytesToSend = composer.make();
		final List<String> list = getSimMNC(activity);
		Thread t = new Thread(() -> {
			//因为在切换apn过程中需要一定时间,所以需要加上一个重试操作
			int retry = 0;
			do {
//				Log.d(TAG, "重试次数:"+(retry+1));
				try {
					if (sendMMMS(list, activity, bytesToSend)) {
						activity.runOnUiThread(()->{
							Toast.makeText(activity, R.string.strOk,
									Toast.LENGTH_LONG).show();
						});
						return;
					}
					retry++;
					Thread.sleep(2000);
				} catch (Exception e) {
					e.printStackTrace();
				}
			} while (retry < 5);
			activity.runOnUiThread(() -> {
				Toast.makeText(activity, R.string.strFail, Toast.LENGTH_LONG).show();
			});
		});
		t.start();
	}
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值