Java tutorial
/* * Copyright (C) 2008 Esmertec AG. * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.mms.ui; import static android.content.res.Configuration.KEYBOARDHIDDEN_NO; import static com.android.mms.transaction.ProgressCallbackEntity.PROGRESS_ABORT; import static com.android.mms.transaction.ProgressCallbackEntity.PROGRESS_COMPLETE; import static com.android.mms.transaction.ProgressCallbackEntity.PROGRESS_START; import static com.android.mms.transaction.ProgressCallbackEntity.PROGRESS_STATUS_ACTION; import static com.android.mms.ui.MessageListAdapter.COLUMN_ID; import static com.android.mms.ui.MessageListAdapter.COLUMN_MMS_LOCKED; import static com.android.mms.ui.MessageListAdapter.COLUMN_MSG_TYPE; import static com.android.mms.ui.MessageListAdapter.COLUMN_SMS_PHONE_ID; import static com.android.mms.ui.MessageListAdapter.PROJECTION; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.regex.Pattern; import org.apache.http.util.EncodingUtils; import android.app.Activity; import android.app.ActivityManager; import android.app.ProgressDialog; import android.app.SimChooserDialog; import android.app.AlertDialog; import android.content.ActivityNotFoundException; import android.content.AsyncQueryHandler; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.DialogInterface.OnClickListener; import android.content.SharedPreferences; import android.content.res.AssetFileDescriptor; import android.content.res.Configuration; import android.content.res.Resources; import android.database.Cursor; import android.database.sqlite.SQLiteException; import android.database.sqlite.SqliteWrapper; import android.drm.mobile1.DrmException; import android.drm.mobile1.DrmRawContent; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.inputmethodservice.InputMethodService; import android.media.CamcorderProfile; import android.media.RingtoneManager; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.os.Environment; import android.os.FileUtils; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.Parcelable; import android.os.SystemProperties; import android.pim.vcard.VCardBuilder; import android.pim.vcard.VCardComposer; import android.pim.vcard.VCardConfig; import android.pim.vcard.VCardComposer.HandlerForOutputStream; import android.preference.PreferenceManager; import android.provider.BaseColumns; import android.provider.ContactsContract; import android.provider.DrmStore; import android.provider.MediaStore; import android.provider.Settings; import android.provider.ContactsContract.Contacts; import android.provider.ContactsContract.CommonDataKinds.Email; import android.provider.ContactsContract.CommonDataKinds.Phone; import android.provider.ContactsContract.CommonDataKinds.StructuredName; import android.provider.MediaStore.Images; import android.provider.MediaStore.Video; import android.provider.Telephony.Mms; import android.provider.Telephony.MmsSms; import android.provider.Telephony.Sms; import android.provider.Telephony.MmsSms.PendingMessages; import android.telephony.PhoneNumberUtils; import android.telephony.SmsManager; import android.telephony.SmsMessage; import android.telephony.TelephonyManager; import android.text.Annotation; import android.text.ClipboardManager; import android.text.Editable; import android.text.InputFilter; import android.text.Selection; import android.text.Spannable; import android.text.SpannableString; import android.text.Spanned; import android.text.TextUtils; import android.text.TextWatcher; import android.text.format.Time; import android.text.method.TextKeyListener; import android.text.style.AbsoluteSizeSpan; import android.text.style.URLSpan; import android.text.util.Linkify; import android.util.Config; import android.util.Log; import android.view.ContextMenu; import android.view.ContextThemeWrapper; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.ViewStub; import android.view.Window; import android.view.WindowManager; import android.view.ContextMenu.ContextMenuInfo; import android.view.View.OnCreateContextMenuListener; import android.view.View.OnKeyListener; import android.view.inputmethod.InputMethodManager; import android.webkit.MimeTypeMap; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.SimpleAdapter; import android.widget.TextView; import android.widget.Toast; import android.widget.LinearLayout.LayoutParams; import com.android.internal.telephony.IccUtils; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyProperties; import com.android.mms.ExceedMessageSizeException; import com.android.mms.LogTag; import com.android.mms.MmsConfig; import com.android.mms.R; import com.android.mms.ResolutionException; import com.android.mms.TempFileProvider; import com.android.mms.UnsupportContentTypeException; import com.android.mms.data.Contact; import com.android.mms.data.ContactList; import com.android.mms.data.Conversation; import com.android.mms.data.WorkingMessage; import com.android.mms.data.WorkingMessage.MessageStatusListener; import com.google.android.mms.ContentType; import com.google.android.mms.pdu.EncodedStringValue; import com.google.android.mms.MmsException; import com.google.android.mms.pdu.PduBody; import com.google.android.mms.pdu.PduHeaders; import com.google.android.mms.pdu.PduPart; import com.google.android.mms.pdu.PduPersister; import com.google.android.mms.pdu.SendReq; import com.android.mms.model.ImageModel; import com.android.mms.model.Model; import com.android.mms.model.TextModel; import com.android.mms.model.SlideModel; import com.android.mms.model.SlideshowModel; import com.android.mms.model.VcardModel; import com.android.mms.transaction.MessageSender; import com.android.mms.transaction.MessagingNotification; import com.android.mms.transaction.MmsMessageSender; import com.android.mms.transaction.SmsReceiver; import com.android.mms.transaction.SmsReceiverService; import com.android.mms.transaction.TransactionService; import com.android.mms.transaction.TransactionServiceHelper; import com.android.mms.ui.MessageUtils.ResizeImageResultCallback; import com.android.mms.ui.RecipientsEditor.RecipientContextMenuInfo; import com.android.mms.util.DownloadManager; import com.android.mms.util.FeatureSwitch; import com.android.mms.util.SendingProgressTokenManager; import com.android.mms.util.SmileyParser; import com.android.mms.util.ZoomViewUtil; import android.text.InputFilter.LengthFilter; import com.android.internal.telephony.PhoneFactory; import com.android.mms.ui.ConversationList;// by lai import android.view.MotionEvent; //by lai import android.widget.ScrollView; //by lai import android.view.View.OnTouchListener; //by lai import android.preference.PreferenceManager;//by lai /** * This is the main UI for: * 1. Composing a new message; * 2. Viewing/managing message history of a conversation. * * This activity can handle following parameters from the intent * by which it's launched. * thread_id long Identify the conversation to be viewed. When creating a * new message, this parameter shouldn't be present. * msg_uri Uri The message which should be opened for editing in the editor. * address String The addresses of the recipients in current conversation. * exit_on_sent boolean Exit this activity after the message is sent. */ public class ComposeMessageActivity extends Activity implements View.OnClickListener, TextView.OnEditorActionListener, MessageStatusListener, Contact.UpdateListener, ZoomViewUtil.TextResizeable { public static final int REQUEST_CODE_ATTACH_IMAGE = 10; public static final int REQUEST_CODE_TAKE_PICTURE = 11; public static final int REQUEST_CODE_ATTACH_VIDEO = 12; public static final int REQUEST_CODE_TAKE_VIDEO = 13; public static final int REQUEST_CODE_ATTACH_SOUND = 14; public static final int REQUEST_CODE_RECORD_SOUND = 15; public static final int REQUEST_CODE_CREATE_SLIDESHOW = 16; public static final int REQUEST_CODE_ECM_EXIT_DIALOG = 17; public static final int REQUEST_CODE_ADD_CONTACT = 18; public static final int REQUEST_CODE_ADD_ATTACHMENT = 19; private static final String TAG = "Mms/compose"; private static final boolean DEBUG = true; private static final boolean TRACE = false; private static final boolean LOCAL_LOGV = DEBUG ? Config.LOGD : Config.LOGV; private static final String EXTRA_IS_VIDEOCALL = "android.phone.extra.IS_VIDEOCALL"; private String mPhoneNumForMms; //by lai // Menu ID private static final int MENU_ADD_SUBJECT = 0; private static final int MENU_DELETE_THREAD = 1; private static final int MENU_ADD_ATTACHMENT = 2; private static final int MENU_DISCARD = 3; private static final int MENU_SEND = 4; private static final int MENU_CALL_RECIPIENT = 5; private static final int MENU_VIDEOCALL_RECIPIENT = 6; private static final int MENU_CONVERSATION_LIST = 7; // Context menu ID private static final int MENU_VIEW_CONTACT = 12; private static final int MENU_ADD_TO_CONTACTS = 13; private static final int MENU_EDIT_MESSAGE = 14; private static final int MENU_VIEW_SLIDESHOW = 16; private static final int MENU_VIEW_MESSAGE_DETAILS = 17; private static final int MENU_DELETE_MESSAGE = 18; private static final int MENU_SEARCH = 19; private static final int MENU_DELIVERY_REPORT = 20; private static final int MENU_FORWARD_MESSAGE = 21; private static final int MENU_CALL_BACK = 22; private static final int MENU_VIDEOCALL_BACK = 23; private static final int MENU_SEND_EMAIL = 24; private static final int MENU_COPY_MESSAGE_TEXT = 25; private static final int MENU_COPY_TO_SDCARD = 26; private static final int MENU_INSERT_SMILEY = 27; private static final int MENU_ADD_ADDRESS_TO_CONTACTS = 28; private static final int MENU_LOCK_MESSAGE = 29; private static final int MENU_UNLOCK_MESSAGE = 30; private static final int MENU_COPY_TO_DRM_PROVIDER = 31; private static final int MENU_COPY_MESSAGE_TO_SIM = 32; private static final int MENU_SEND_SMS = 33; private static final int MENU_COPY_MMS_MESSAGE_TEXT = 34; //===== fixed CR<NEWMS00120677> by luning at 11-09-17 begin===== private static final int MENU_SAVE_BOOKMARK = 34; private static final String ACTION_SAVE_BOOKMARK = "sprd.intent.action.SAVE_BOOKMARK"; //===== fixed CR<NEWMS00120677> by luning at 11-09-17 end===== private static final int MENU_RESEND_MESSAGE = 35; //===== fixed CR<NEWSM00125959> by luning at 11-09-26 begin ===== private static boolean IS_APPEND_MEDIA = true; //===== fixed CR<NEWSM00125959> by luning at 11-09-26 end ===== //private static final int RECIPIENTS_MAX_LENGTH = 312; private static final int RECIPIENTS_MAX_LENGTH = 2000; // the max muber of recipients to send message private static final int RECIPIENTS_MAX_MUBER = 200; private static final int MESSAGE_LIST_QUERY_TOKEN = 9527; private static final int DELETE_MESSAGE_TOKEN = 9700; private static final int CHARS_REMAINING_BEFORE_COUNTER_SHOWN = 10; private static final long NO_DATE_FOR_DIALOG = -1L; //yeezone:jinwei add limit of private static final int LIMITED_MESSAGE_MAX_COUNT = 160;//modify from 140 to 160 for for wrong max message count 20110722 private static final int REQUESET_CODE_SELECT_CONTACTS = 1000; private static final String EXIT_ECM_RESULT = "exit_ecm_result"; private static final int MODE_MMS_VCARD_CONTACTS = 8; //for include vcard private ContentResolver mContentResolver; private BackgroundQueryHandler mBackgroundQueryHandler; private Conversation mConversation; // Conversation we are working in private boolean mExitOnSent; // Should we finish() after sending a message? private TextView mTitleLeft; //left of title private TextView mTitleRight; //right of title private View mTopPanel; // View containing the recipient and subject editors private View mBottomPanel; // View containing the text editor, send button, ec. private EditText mTextEditor; // Text editor to type your message into private TextView mTextCounter; // Shows the number of characters used in text editor private Button mSendButton; // Press to detonate private Button mContactsSelectButton; // Press to select number from Contacts //yeezone:jinwei private EditText mSubjectTextEditor; // Text editor for MMS subject private AttachmentEditor mAttachmentEditor; private SimChooserDialog mSimChooserDialg; private TelephonyManager mTelephonyManager; private MessageListView mMsgListView; // ListView for messages in this conversation public MessageListAdapter mMsgListAdapter; // and its corresponding ListAdapter private RecipientsEditor mRecipientsEditor; // UI control for editing recipients private boolean mIsKeyboardOpen; // Whether the hardware keyboard is visible private boolean mIsLandscape; // Whether we're in landscape mode private boolean mPossiblePendingNotification; // If the message list has changed, we may have // a pending notification to deal with. private boolean mToastForDraftSave; // Whether to notify the user that a draft is being saved private boolean mSentMessage; // true if the user has sent a message while in this // activity. On a new compose message case, when the first // message is sent is a MMS w/ attachment, the list blanks // for a second before showing the sent message. But we'd // think the message list is empty, thus show the recipients // editor thinking it's a draft message. This flag should // help clarify the situation. private WorkingMessage mWorkingMessage; // The message currently being composed. private AlertDialog mSmileyDialog; private boolean mWaitingForSubActivity; private int mLastRecipientCount; // Used for warning the user on too many recipients. private AttachmentTypeSelectorAdapter mAttachmentTypeSelectorAdapter; private boolean mSendingMessage; // Indicates the current message is sending, and shouldn't send again. private Intent mAddContactIntent; // Intent used to add a new contact // add save all send Contacts // private ArrayList<ContentValues> list = new ArrayList<ContentValues>();/*delete for CR<NEWMS00135995> by luning at 11-11-04 */ private boolean[] mSmsReady = { false, false }; AlertDialog.Builder mAttachmentDialogBuilder; AlertDialog mAttachmentDialog; //modify by dory.zheng for NEWMS00120648 at 15-09 begin static final Uri DIVIDED_GROUP_URI = Uri.parse("content://" + ContactsContract.AUTHORITY + "/divided_group"); private final static int MODE_PICK = 0; private static final int GROUP_ALL = 0; private static final int GROUP_PHONE = 1; private static final int GROUP_SIM = 2; private static final int GROUP_SIM1 = 4; private static final int GROUP_SIM2 = 5; //modify by dory.zheng for NEWMS00120648 at 15-09 end /* fixed CR<NEWMS119944 NEWMS119757 NEWMS119755 NEWMS120030 NEWMS119256> by lino release memory */ private Cursor mCursor; private LinearLayout mContextView; // private boolean mCreate; private String mDebugRecipients; private static final String INBOX = "inbox"; private static final String OUTBOX = "outbox"; private static final String SENT = "sent"; private static final String DRAFTS = "drafts"; private String boxmsgFlg = ""; private String boxmsgThreadId = ""; private String boxmsgMsgId = ""; private String boxType = ""; private String messageBody; private boolean isLongPressSendFlg = false; static final String MMS_LAUNCH_MODE_PATH = "/data/data/com.android.mms/launchmode"; private static final int GROUP_NAME_STUDENT = 0; private static final int GROUP_NAME_FRIEND = 1; private static final int GROUP_NAME_FAMILY = 2; private static final int GROUP_NAME_COLLEAGUE = 3; private boolean outboxEditMsgFlg = false; private boolean is_vcard_adding = false; private ProgressDialog mVcardProgressDialog = null; private VcardProgressHandler mEventHandler = null; //add for bug 17466 private boolean notificationFlg = false; private ZoomViewUtil mZoom; private static enum TextCompareResult { NOEXCEED_ANY_SIZE, EXCEED_MAX_MMS_SIZE, EXCEED_MAX_TEXT_SIZE, EXCEED_ORGINAL_MAX_MMS_SIZE; } private TextCompareResult mTxtCompareRst = TextCompareResult.NOEXCEED_ANY_SIZE; private int mTxtLength = 0; @SuppressWarnings("unused") private static void log(String logMsg) { Thread current = Thread.currentThread(); long tid = current.getId(); StackTraceElement[] stack = current.getStackTrace(); String methodName = stack[3].getMethodName(); // Prepend current thread ID and name of calling method to the message. logMsg = "[" + tid + "] [" + methodName + "] " + logMsg; Log.d(TAG, logMsg); } //========================================================== // Inner classes //========================================================== private void editSlideshow() { /* fixed HUAWEI BUG by luning at 2011.12.27 begin*/ if (mWorkingMessage.isDiscarded()) { mWorkingMessage.unDiscard(); } /* fixed HUAWEI BUG by luning at 2011.12.27 end*/ Uri dataUri = mWorkingMessage.saveAsMms(false); Intent intent = new Intent(this, SlideshowEditActivity.class); intent.setData(dataUri); startActivityForResult(intent, REQUEST_CODE_CREATE_SLIDESHOW); } private String getDeafaultGroupName(int groupNameId) { String groupName = ""; switch (groupNameId) { case GROUP_NAME_STUDENT: // ContentValues values1 = new ContentValues(); groupName = this.getString(R.string.group_name_student); // values1.put("divided_name", groupName); // this.getContentResolver().update(DIVIDED_GROUP_URI, values1, "_id=" + groupNameId, null); break; case GROUP_NAME_FRIEND: // ContentValues values2 = new ContentValues(); groupName = this.getString(R.string.group_name_friend); // values2.put("divided_name", groupName); // this.getContentResolver().update(DIVIDED_GROUP_URI, values2, "_id=" + groupNameId, null); break; case GROUP_NAME_FAMILY: // ContentValues values3 = new ContentValues(); groupName = this.getString(R.string.group_name_family); // values3.put("divided_name", groupName); // this.getContentResolver().update(DIVIDED_GROUP_URI, values3, "_id=" + groupNameId, null); break; case GROUP_NAME_COLLEAGUE: // ContentValues values4 = new ContentValues(); groupName = this.getString(R.string.group_name_colleague); // values4.put("divided_name", groupName); // this.getContentResolver().update(DIVIDED_GROUP_URI, values4, "_id=" + groupNameId, null); break; default: break; } return groupName; } private Handler mAttachmentEditorHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case AttachmentEditor.MSG_EDIT_SLIDESHOW: { editSlideshow(); break; } case AttachmentEditor.MSG_SEND_SLIDESHOW: { if (isPreparedForSending()) { ComposeMessageActivity.this.confirmSendMessageIfNeeded(); } break; } case AttachmentEditor.MSG_VIEW_IMAGE: case AttachmentEditor.MSG_PLAY_VIDEO: case AttachmentEditor.MSG_PLAY_AUDIO: case AttachmentEditor.MSG_PLAY_SLIDESHOW: MessageUtils.viewMmsMessageAttachment(ComposeMessageActivity.this, mWorkingMessage); break; case AttachmentEditor.MSG_REPLACE_IMAGE: case AttachmentEditor.MSG_REPLACE_VIDEO: case AttachmentEditor.MSG_REPLACE_AUDIO: //===== fixed CR<NEWSM00125959> by luning at 11-09-26 begin ===== IS_APPEND_MEDIA = false; //===== fixed CR<NEWSM00125959> by luning at 11-09-26 end ===== showAddAttachmentDialog(true); break; case AttachmentEditor.MSG_REMOVE_ATTACHMENT: //CR NEWMS00107285 Modify Start //yuechao fix for bug 10371 start if (!isSubjectEditorVisible() || mSubjectTextEditor.length() == 0) { showSubjectEditor(false); mWorkingMessage.setSubject(null, true); } //yuechao fix for bug 10371 end //CR NEWMS00107285 Modify End mWorkingMessage.setAttachment(WorkingMessage.TEXT, null, false); break; // ======fixed CR<NEWMS00120798> by luning at 2011.11.09 begin====== case AttachmentEditor.MSG_VIEW_VCARD: VcardModel vcardmodel = mWorkingMessage.getSlideshow().mVcards.get(0); String detail = vcardmodel.getDetail(); String name = vcardmodel.getSrc(); if (null == detail || detail.length() <= 0) { detail = getString(R.string.cannot_get_details); } new AlertDialog.Builder(ComposeMessageActivity.this).setIcon(R.drawable.vcf).setTitle(name) .setMessage(detail).setPositiveButton(getString(R.string.yes), null).show(); break; // ======fixed CR<NEWMS00120798> by luning at 2011.11.09 end====== default: break; } } }; private Handler mMessageListItemHandler = new Handler() { @Override public void handleMessage(Message msg) { String type; switch (msg.what) { case MessageListItem.MSG_LIST_EDIT_MMS: type = "mms"; break; case MessageListItem.MSG_LIST_EDIT_SMS: type = "sms"; break; default: Log.w(TAG, "Unknown message: " + msg.what); return; } MessageItem msgItem = getMessageItem(type, (Long) msg.obj, false); if (msgItem != null) { editMessageItem(msgItem); drawBottomPanel(); } } }; private Handler mMessageOperationHandler = new Handler() { @Override public void handleMessage(Message msg) { if (msg == null) { return; } switch (msg.what) { case MENU_COPY_MESSAGE_TO_SIM: Log.d(TAG, "Do copy message to sim"); Bundle bun = msg.getData(); if (bun != null) { String type = bun.getString("type"); Long msgId = bun.getLong("msgId", -1); int phoneId = bun.getInt("PhoneId", -1); Log.i(TAG, "Do copy message to sim type is" + type); Log.i(TAG, "Do copy message to sim msgId is" + msgId); Log.i(TAG, "Do copy message to sim phoneId is" + phoneId); MessageItem msgItem = getMessageItem(type, msgId, true); if (msgItem != null) { copyMessageToSim(msgItem, phoneId); } else { Log.i(TAG, "Do copy message to sim getMessageItem(type, msgId, true) is null"); } } else { Log.i(TAG, "Do copy message to sim msg.getData() is null"); } break; default: Log.w(TAG, "Unknown message: " + msg.what); return; } } }; private OnKeyListener mSubjectKeyListener = new OnKeyListener() { public boolean onKey(View v, int keyCode, KeyEvent event) { if (event.getAction() != KeyEvent.ACTION_DOWN) { return false; } // When the subject editor is empty, press "DEL" to hide the input field. if ((keyCode == KeyEvent.KEYCODE_DEL) && (mSubjectTextEditor.length() == 0)) { showSubjectEditor(false); mWorkingMessage.setSubject(null, true); return true; } return false; } }; /** * Return the messageItem associated with the type ("mms" or "sms") and message id. * @param type Type of the message: "mms" or "sms" * @param msgId Message id of the message. This is the _id of the sms or pdu row and is * stored in the MessageItem * @param createFromCursorIfNotInCache true if the item is not found in the MessageListAdapter's * cache and the code can create a new MessageItem based on the position of the current cursor. * If false, the function returns null if the MessageItem isn't in the cache. * @return MessageItem or null if not found and createFromCursorIfNotInCache is false */ private MessageItem getMessageItem(String type, long msgId, boolean createFromCursorIfNotInCache) { return mMsgListAdapter.getCachedMessageItem(type, msgId, createFromCursorIfNotInCache ? mMsgListAdapter.getCursor() : null); } private boolean isCursorValid() { // Check whether the cursor is valid or not. Cursor cursor = mMsgListAdapter.getCursor(); if (cursor.isClosed() || cursor.isBeforeFirst() || cursor.isAfterLast()) { Log.e(TAG, "Bad cursor.", new RuntimeException()); return false; } return true; } private void resetCounter() { mTextCounter.setText(""); mTextCounter.setVisibility(View.GONE); } //2012-02-14 fix for bug 10574 private void reCalcSmsCounter(CharSequence text) { WorkingMessage workingMessage = mWorkingMessage; int[] params = SmsMessage.calculateLength(text, false); /* SmsMessage.calculateLength returns an int[4] with: * int[0] being the number of SMS's required, * int[1] the number of code units used, * int[2] is the number of code units remaining until the next message. * int[3] is the encoding type that should be used for the message. */ int msgCount = params[0]; int remainingInCurrentMessage = params[2]; boolean showCounter = true; if (showCounter) { // Update the remaining characters and number of messages required. String counterText = msgCount > 1 ? remainingInCurrentMessage + "/" + msgCount : String.valueOf(remainingInCurrentMessage) + "/" + 1; mTextCounter.setText(counterText); //mTitleRight.setText(counterText); mTextCounter.setVisibility(View.VISIBLE); } else { mTextCounter.setVisibility(View.GONE); } } private void updateCounter(CharSequence text, int start, int before, int count) { WorkingMessage workingMessage = mWorkingMessage; // if (workingMessage.requiresMms()) { // // If we're not removing text (i.e. no chance of converting back to SMS // // because of this change) and we're in MMS mode, just bail out since we // // then won't have to calculate the length unnecessarily. // final boolean textRemoved = (before > count); // if (!textRemoved) { // setSendButtonText(workingMessage.requiresMms()); // return; // } // } int[] params = SmsMessage.calculateLength(text, false); /* SmsMessage.calculateLength returns an int[4] with: * int[0] being the number of SMS's required, * int[1] the number of code units used, * int[2] is the number of code units remaining until the next message. * int[3] is the encoding type that should be used for the message. */ int msgCount = params[0]; if (workingMessage.requiresMms()) { // If we're not removing text (i.e. no chance of converting back to SMS // because of this change) and we're in MMS mode, just bail out since we // then won't have to calculate the length unnecessarily. final boolean textRemoved = (before > count); if (!textRemoved) { setSendButtonText(workingMessage.requiresMms()); //fix for bug 10574 start phone02 if (msgCount > MmsConfig.getSmsToMmsTextThreshold()) { mWorkingMessage.setLengthRequiresMms(msgCount > MmsConfig.getSmsToMmsTextThreshold(), true); } //fix for bug 10574 phone02 end return; } } // === modify by luning for NEWMS00107396 at 11-09-02 begin === if (msgCount >= 11 && !workingMessage.requiresMms()/*fixed CR<NEWMS00148018> by luning at 2011.12.21 */) { /* modify by luning for HUAWEI bug at 2011.12.27 begin */ SmsManager smsManager = SmsManager.getDefault(); ArrayList<String> messages = smsManager.divideMessage(text.toString()); StringBuilder sb = new StringBuilder(); for (int i = 0; i < 10; i++) { sb.append(messages.get(i)); } mTextEditor.setText(sb.subSequence(0, sb.length())); // mTextEditor.setText(text.subSequence(0, start)); /* modify by luning for HUAWEI bug at 2011.12.27 end */ Selection.setSelection(mTextEditor.getText(), mTextEditor.length()); return; } // === modify by luning for NEWMS00107396 at 11-09-02 end === int remainingInCurrentMessage = params[2]; //update by spreadst_lishengjie start 2012-1-30 : fix bug9176 //if (!MmsConfig.getMultipartSmsEnabled()) { mWorkingMessage.setLengthRequiresMms(msgCount > MmsConfig.getSmsToMmsTextThreshold(), true); //} //update by spreadst_lishengjie end 2012-1-30 // Show the counter only if: // - We are not in MMS mode // - We are going to send more than one message OR we are getting close //boolean showCounter = false; boolean showCounter = true; //===== fixed CR<NEWMS00134916> by luning at 11-10-28 begin ===== // if (!workingMessage.requiresMms() && // (msgCount > 1 || // remainingInCurrentMessage <= CHARS_REMAINING_BEFORE_COUNTER_SHOWN)) { // showCounter = true; // } if (workingMessage.requiresMms()) { showCounter = false; } //===== fixed CR<NEWMS00134916> by luning at 11-10-28 begin ===== setSendButtonText(workingMessage.requiresMms()); if (showCounter) { // Update the remaining characters and number of messages required. String counterText = msgCount > 1 ? remainingInCurrentMessage + "/" + msgCount : String.valueOf(remainingInCurrentMessage) + "/" + 1; mTextCounter.setText(counterText); //mTitleRight.setText(counterText); mTextCounter.setVisibility(View.VISIBLE); } else { mTextCounter.setVisibility(View.GONE); } } @Override public void startActivityForResult(Intent intent, int requestCode) { // requestCode >= 0 means the activity in question is a sub-activity. if (requestCode >= 0) { mWaitingForSubActivity = true; } super.startActivityForResult(intent, requestCode); } private void toastConvertInfo(boolean toMms) { final int resId = toMms ? R.string.converting_to_picture_message : R.string.converting_to_text_message; Toast.makeText(this, resId, Toast.LENGTH_SHORT).show(); } private class DeleteMessageListener implements OnClickListener { private final Uri mDeleteUri; private final boolean mDeleteLocked; public DeleteMessageListener(Uri uri, boolean deleteLocked) { mDeleteUri = uri; mDeleteLocked = deleteLocked; } public DeleteMessageListener(long msgId, String type, boolean deleteLocked) { if ("mms".equals(type)) { mDeleteUri = ContentUris.withAppendedId(Mms.CONTENT_URI, msgId); } else { mDeleteUri = ContentUris.withAppendedId(Sms.CONTENT_URI, msgId); } mDeleteLocked = deleteLocked; } public void onClick(DialogInterface dialog, int whichButton) { mBackgroundQueryHandler.startDelete(DELETE_MESSAGE_TOKEN, null, mDeleteUri, mDeleteLocked ? null : "locked=0", null); dialog.dismiss(); } } private class DiscardDraftListener implements OnClickListener { public void onClick(DialogInterface dialog, int whichButton) { //modify by liguxiang 10-11-11 for NEWM00129822 begin if (whichButton == dialog.BUTTON_POSITIVE) { mWorkingMessage.discard(); finish(); } else if (whichButton == dialog.BUTTON_NEUTRAL) { mToastForDraftSave = true; saveDraft(); finish(); } //modify by liguxiang 10-11-11 for NEWM00129822 end // mWorkingMessage.discard(); // dialog.dismiss(); // finish(); } } private class SendIgnoreInvalidRecipientListener implements OnClickListener { public void onClick(DialogInterface dialog, int whichButton) { sendMessage(true); dialog.dismiss(); } } private class CancelSendingListener implements OnClickListener { public void onClick(DialogInterface dialog, int whichButton) { if (isRecipientsEditorVisible()) { mRecipientsEditor.requestFocus(); } dialog.dismiss(); } } private void confirmSendMessageIfNeeded() { boolean isMms = mWorkingMessage.requiresMms(); //20120204 start if (isMms) { //check the mms size beyond the limit,when send the mms message SlideshowModel slideshow = mWorkingMessage.getSlideshow(); if (slideshow != null) { long mmssize = slideshow.getTotalMsgSizeWithAllHead(); Log.d(TAG, "mmssize:" + mmssize); if (DownloadManager.getInstance().checkMmsSizeLimit(mmssize)) { runOnUiThread(new Runnable() { public void run() { String title = ComposeMessageActivity.this.getResources() .getString(R.string.exceed_message_size_limitation); String message = ComposeMessageActivity.this.getResources() .getString(R.string.exceed_message_size_limitation); MessageUtils.showErrorDialog(ComposeMessageActivity.this, title, message); } }); return; } } } //20120204 start if (!isRecipientsEditorVisible()) { sendMessage(true); return; } if (mRecipientsEditor.hasInvalidRecipient(isMms)) { if (mRecipientsEditor.hasValidRecipient(isMms)) { String title = getResourcesString(R.string.has_invalid_recipient, mRecipientsEditor.formatInvalidNumbers(isMms)); new AlertDialog.Builder(this).setIcon(android.R.drawable.ic_dialog_alert).setTitle(title) .setMessage(R.string.invalid_recipient_message) .setPositiveButton(R.string.try_to_send, new SendIgnoreInvalidRecipientListener()) .setNegativeButton(R.string.no, new CancelSendingListener()).show(); } else { new AlertDialog.Builder(this).setIcon(android.R.drawable.ic_dialog_alert) .setTitle(R.string.cannot_send_message).setMessage(R.string.cannot_send_message_reason) .setPositiveButton(R.string.yes, new CancelSendingListener()).show(); } } else { sendMessage(true); } if (MessageUtils.isMSMS) { //TODO } else { if (isSomeSmsUnReady()) { Toast.makeText(this, this.getResources().getString(R.string.sim_no_ready), Toast.LENGTH_LONG) .show(); } } } public boolean isSomeSmsUnReady() { if (TelephonyManager.getPhoneCount() <= 1) { if (!mSmsReady[0]) { return true; } else { return false; } } else { if (mWorkingMessage != null) { if (!mSmsReady[mWorkingMessage.getPhoneId()]) { return true; } else { return false; } } else { if (!mSmsReady[0] && !mSmsReady[1]) { return true; } else { return false; } } } } private TextWatcher mRecipientsWatcher = new TextWatcher() { public void beforeTextChanged(CharSequence s, int start, int count, int after) { } public void onTextChanged(CharSequence s, int start, int before, int count) { // This is a workaround for bug 1609057. Since onUserInteraction() is // not called when the user touches the soft keyboard, we pretend it was // called when textfields changes. This should be removed when the bug // is fixed. onUserInteraction(); } public void afterTextChanged(Editable s) { // Bug 1474782 describes a situation in which we send to // the wrong recipient. We have been unable to reproduce this, // but the best theory we have so far is that the contents of // mRecipientList somehow become stale when entering // ComposeMessageActivity via onNewIntent(). This assertion is // meant to catch one possible path to that, of a non-visible // mRecipientsEditor having its TextWatcher fire and refreshing // mRecipientList with its stale contents. if (!isRecipientsEditorVisible()) { IllegalStateException e = new IllegalStateException( "afterTextChanged called with invisible mRecipientsEditor"); // Make sure the crash is uploaded to the service so we // can see if this is happening in the field. Log.w(TAG, "RecipientsWatcher: afterTextChanged called with invisible mRecipientsEditor"); return; } mWorkingMessage.setWorkingRecipients(mRecipientsEditor.getNumbers()); mWorkingMessage.setHasEmail(mRecipientsEditor.containsEmail(), true); checkForTooManyRecipients(); // Walk backwards in the text box, skipping spaces. If the last // character is a comma, update the title bar. for (int pos = s.length() - 1; pos >= 0; pos--) { char c = s.charAt(pos); if (c == ' ') continue; if (c == ',') { updateTitle(mConversation.getRecipients()); } break; } // fix bug 13720 start if (s.length() == 0) { mConversation.setRecipients(new ContactList()); updateTitle(mConversation.getRecipients()); } // fix bug 13720 end // If we have gone to zero recipients, disable send button. updateSendButtonState(); } }; private void checkForTooManyRecipients() { final int recipientLimit = MmsConfig.getRecipientLimit(); if (recipientLimit != Integer.MAX_VALUE) { final int recipientCount = recipientCount(); boolean tooMany = recipientCount > recipientLimit; if (recipientCount != mLastRecipientCount) { // Don't warn the user on every character they type when they're over the limit, // only when the actual # of recipients changes. mLastRecipientCount = recipientCount; if (tooMany) { String tooManyMsg = getString(R.string.too_many_recipients, recipientCount, recipientLimit); Toast.makeText(ComposeMessageActivity.this, tooManyMsg, Toast.LENGTH_LONG).show(); } } } } private OnCreateContextMenuListener mRecipientsMenuCreateListener = new OnCreateContextMenuListener() { public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { if (menuInfo != null) { Contact c = ((RecipientContextMenuInfo) menuInfo).recipient; RecipientsMenuClickListener l = new RecipientsMenuClickListener(c); menu.setHeaderTitle(c.getName()); if (c.existsInDatabase()) { menu.add(0, MENU_VIEW_CONTACT, 0, R.string.menu_view_contact).setOnMenuItemClickListener(l); } else if (canAddToContacts(c)) { menu.add(0, MENU_ADD_TO_CONTACTS, 0, R.string.menu_add_to_contacts) .setOnMenuItemClickListener(l); } } } }; private class RecipientsMenuClickListener implements MenuItem.OnMenuItemClickListener { private final Contact mRecipient; RecipientsMenuClickListener(Contact recipient) { mRecipient = recipient; } public boolean onMenuItemClick(MenuItem item) { switch (item.getItemId()) { // Context menu handlers for the recipients editor. case MENU_VIEW_CONTACT: { Uri contactUri = mRecipient.getUri(); Intent intent = new Intent(Intent.ACTION_VIEW, contactUri); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); startActivityForResult(intent, 0); return true; } case MENU_ADD_TO_CONTACTS: { mAddContactIntent = ConversationList.createAddContactIntent(mRecipient.getNumber()); ComposeMessageActivity.this.startActivityForResult(mAddContactIntent, REQUEST_CODE_ADD_CONTACT); return true; } } return false; } } private boolean canAddToContacts(Contact contact) { // There are some kind of automated messages, like STK messages, that we don't want // to add to contacts. These names begin with special characters, like, "*Info". final String name = contact.getName(); if (!TextUtils.isEmpty(contact.getNumber())) { char c = contact.getNumber().charAt(0); if (isSpecialChar(c)) { return false; } } if (!TextUtils.isEmpty(name)) { char c = name.charAt(0); if (isSpecialChar(c)) { return false; } } if (!(Mms.isEmailAddress(name) || Mms.isPhoneNumber(name) || MessageUtils.isLocalNumber(contact.getNumber()))) { // Handle "Me" return false; } return true; } private boolean isSpecialChar(char c) { return c == '*' || c == '%' || c == '$'; } private void addPositionBasedMenuItems(ContextMenu menu, View v, ContextMenuInfo menuInfo) { AdapterView.AdapterContextMenuInfo info; try { info = (AdapterView.AdapterContextMenuInfo) menuInfo; } catch (ClassCastException e) { Log.e(TAG, "bad menuInfo"); return; } final int position = info.position; addUriSpecificMenuItems(menu, v, position); } private Uri getSelectedUriFromMessageList(ListView listView, int position) { // If the context menu was opened over a uri, get that uri. MessageListItem msglistItem = (MessageListItem) listView.getChildAt(position); if (msglistItem == null) { // FIXME: Should get the correct view. No such interface in ListView currently // to get the view by position. The ListView.getChildAt(position) cannot // get correct view since the list doesn't create one child for each item. // And if setSelection(position) then getSelectedView(), // cannot get corrent view when in touch mode. return null; } TextView textView; CharSequence text = null; int selStart = -1; int selEnd = -1; //check if message sender is selected textView = (TextView) msglistItem.findViewById(R.id.text_view); if (textView != null) { text = textView.getText(); selStart = textView.getSelectionStart(); selEnd = textView.getSelectionEnd(); } if (selStart == -1) { //sender is not being selected, it may be within the message body textView = (TextView) msglistItem.findViewById(R.id.body_text_view); if (textView != null) { text = textView.getText(); selStart = textView.getSelectionStart(); selEnd = textView.getSelectionEnd(); } } // Check that some text is actually selected, rather than the cursor // just being placed within the TextView. if (selStart != selEnd) { int min = Math.min(selStart, selEnd); int max = Math.max(selStart, selEnd); URLSpan[] urls = ((Spanned) text).getSpans(min, max, URLSpan.class); if (urls.length == 1) { return Uri.parse(urls[0].getURL()); } } //no uri was selected return null; } private void addUriSpecificMenuItems(ContextMenu menu, View v, int position) { Uri uri = getSelectedUriFromMessageList((ListView) v, position); if (uri != null) { Intent intent = new Intent(null, uri); intent.addCategory(Intent.CATEGORY_SELECTED_ALTERNATIVE); menu.addIntentOptions(0, 0, 0, new android.content.ComponentName(this, ComposeMessageActivity.class), null, intent, 0, null); } } private final void addCallAndContactMenuItems(ContextMenu menu, MsgListMenuClickListener l, MessageItem msgItem) { // Add all possible links in the address & message StringBuilder textToSpannify = new StringBuilder(); if (msgItem.mBoxId == Mms.MESSAGE_BOX_INBOX) { textToSpannify.append(msgItem.mAddress + ": "); } textToSpannify.append(msgItem.mBody); SpannableString msg = new SpannableString(textToSpannify.toString()); //===== fixed CR<NEWMS00120677> by luning at 11-09-17 begin===== // Linkify.addLinks(msg, Linkify.ALL); Linkify.findLinks(msg, Linkify.ALL); //===== fixed CR<NEWMS00120677> by luning at 11-09-17 end===== ArrayList<String> uris = MessageUtils.extractUris(msg.getSpans(0, msg.length(), URLSpan.class)); //===== fixed CR<NEWMS00120677> by luning at 11-09-17 begin===== ArrayList<String> webLinks = null; //===== fixed CR<NEWMS00120677> by luning at 11-09-17 end===== while (uris.size() > 0) { String uriString = uris.remove(0); // Remove any dupes so they don't get added to the menu multiple // times while (uris.contains(uriString)) { uris.remove(uriString); } int sep = uriString.indexOf(":"); String prefix = null; if (sep >= 0) { prefix = uriString.substring(0, sep); uriString = uriString.substring(sep + 1); } boolean addToContacts = false; if ("mailto".equalsIgnoreCase(prefix)) { String sendEmailString = getString(R.string.menu_send_email).replace("%s", uriString); Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("mailto:" + uriString)); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); menu.add(0, MENU_SEND_EMAIL, 0, sendEmailString).setOnMenuItemClickListener(l).setIntent(intent); addToContacts = !haveEmailContact(uriString); } else if ("tel".equalsIgnoreCase(prefix)) { boolean bIsSendSMS = true; String callBackString = getString(R.string.menu_call_back).replace("%s", uriString); Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + uriString)); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); if (!msgItem.isWapPush) { menu.add(0, MENU_CALL_BACK, 0, callBackString).setOnMenuItemClickListener(l).setIntent(intent); } if (TelephonyManager.MODEM_TYPE_TDSCDMA == TelephonyManager.getDefault().getModemType() && !msgItem.isWapPush && SystemProperties.getBoolean("ro.device.support.vt", true)) { callBackString = getString(R.string.menu_videocall_back).replace("%s", uriString); intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + uriString)); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); menu.add(0, MENU_VIDEOCALL_BACK, 0, callBackString).setOnMenuItemClickListener(l) .setIntent(getVPIntent(intent)); } if (bIsSendSMS) { callBackString = getString(R.string.menu_send_sms).replace("%s", uriString); intent = new Intent(Intent.ACTION_SENDTO, Uri.parse("smsto:" + uriString)); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); menu.add(0, MENU_SEND_SMS, 0, callBackString).setOnMenuItemClickListener(l).setIntent(intent); } addToContacts = !isNumberInContacts(uriString); } // ===== fixed CR<NEWMS00120677> by luning at 11-09-17 begin===== else if ("http".equalsIgnoreCase(prefix)) { if (null == webLinks) { webLinks = new ArrayList<String>(); } webLinks.add("http:" + uriString); } // ===== fixed CR<NEWMS00120677> by luning at 11-09-17 end===== if (addToContacts && !msgItem.isWapPush) { Intent intent = ConversationList.createAddContactIntent(uriString); String addContactString = getString(R.string.menu_add_address_to_contacts).replace("%s", uriString); menu.add(0, MENU_ADD_ADDRESS_TO_CONTACTS, 0, addContactString).setOnMenuItemClickListener(l) .setIntent(intent); } } //===== fixed CR<NEWMS00120677> by luning at 11-09-17 begin===== if (null != webLinks && webLinks.size() > 0) { Intent intent = new Intent(); intent.putExtra("webLinks", webLinks); menu.add(0, MENU_SAVE_BOOKMARK, 0, getString(R.string.save_to_bookmarks)).setOnMenuItemClickListener(l) .setIntent(intent); } //===== fixed CR<NEWMS00120677> by luning at 11-09-17 end===== } private boolean haveEmailContact(String emailAddress) { Cursor cursor = SqliteWrapper.query(this, getContentResolver(), Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode(emailAddress)), new String[] { Contacts.DISPLAY_NAME }, null, null, null); if (cursor != null) { try { while (cursor.moveToNext()) { String name = cursor.getString(0); if (!TextUtils.isEmpty(name)) { return true; } } } finally { cursor.close(); } } return false; } private boolean isNumberInContacts(String phoneNumber) { return Contact.get(phoneNumber, false).existsInDatabase(); } private OnCreateContextMenuListener mMsgListMenuCreateListener = new OnCreateContextMenuListener() { public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { Cursor cursor = mMsgListAdapter.getCursor(); String type = cursor.getString(COLUMN_MSG_TYPE); long msgId = cursor.getLong(COLUMN_ID); addPositionBasedMenuItems(menu, v, menuInfo); MessageItem msgItem = mMsgListAdapter.getCachedMessageItem(type, msgId, cursor); MessageListItem mli = (MessageListItem) ((AdapterView.AdapterContextMenuInfo) menuInfo).targetView; if (msgItem == null) { Log.e(TAG, "Cannot load message item for type = " + type + ", msgId = " + msgId); return; } menu.setHeaderTitle(R.string.message_options); MsgListMenuClickListener l = new MsgListMenuClickListener(); if (msgItem.mLocked) { menu.add(0, MENU_UNLOCK_MESSAGE, 0, R.string.menu_unlock).setOnMenuItemClickListener(l); } else { menu.add(0, MENU_LOCK_MESSAGE, 0, R.string.menu_lock).setOnMenuItemClickListener(l); } if (msgItem.isMms()) { switch (msgItem.mBoxId) { case Mms.MESSAGE_BOX_INBOX: break; case Mms.MESSAGE_BOX_OUTBOX: // Since we currently break outgoing messages to multiple // recipients into one message per recipient, only allow // editing a message for single-recipient conversations. if (getRecipients().size() == 1) { menu.add(0, MENU_EDIT_MESSAGE, 0, R.string.menu_edit).setOnMenuItemClickListener(l); } break; } switch (msgItem.mAttachmentType) { case WorkingMessage.TEXT: break; case WorkingMessage.VIDEO: case WorkingMessage.IMAGE: if (haveSomethingToCopyToSDCard(msgItem.mMsgId)) { menu.add(0, MENU_COPY_TO_SDCARD, 0, R.string.copy_to_sdcard).setOnMenuItemClickListener(l); } break; case WorkingMessage.VCARD: break; case WorkingMessage.SLIDESHOW: default: menu.add(0, MENU_VIEW_SLIDESHOW, 0, R.string.view_slideshow).setOnMenuItemClickListener(l); if (haveSomethingToCopyToSDCard(msgItem.mMsgId)) { menu.add(0, MENU_COPY_TO_SDCARD, 0, R.string.copy_to_sdcard).setOnMenuItemClickListener(l); } if (haveSomethingToCopyToDrmProvider(msgItem.mMsgId)) { menu.add(0, MENU_COPY_TO_DRM_PROVIDER, 0, getDrmMimeMenuStringRsrc(msgItem.mMsgId)) .setOnMenuItemClickListener(l); } break; } messageBody = mli.getBodyTextView().getText().toString(); if (!TextUtils.isEmpty(messageBody)) { menu.add(0, MENU_COPY_MMS_MESSAGE_TEXT, 0, R.string.copy_message_text) .setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { copyToClipboard(messageBody); return true; } }); } } else { // Message type is sms. Only allow "edit" if the message has a single recipient if (getRecipients().size() == 1 && (msgItem.mBoxId == Sms.MESSAGE_TYPE_OUTBOX || msgItem.mBoxId == Sms.MESSAGE_TYPE_FAILED)) { menu.add(0, MENU_EDIT_MESSAGE, 0, R.string.menu_edit).setOnMenuItemClickListener(l); } } addCallAndContactMenuItems(menu, l, msgItem); // Forward is not available for undownloaded messages. if (msgItem.isDownloaded()) { menu.add(0, MENU_FORWARD_MESSAGE, 0, R.string.menu_forward).setOnMenuItemClickListener(l); } // resent message when sms send failed if (msgItem.isFailedMessage()) {//&& msgItem.isSms() menu.add(0, MENU_RESEND_MESSAGE, 0, R.string.menu_resend).setOnMenuItemClickListener(l); } // It is unclear what would make most sense for copying an MMS message // to the clipboard, so we currently do SMS only. if (msgItem.isSms()) { menu.add(0, MENU_COPY_MESSAGE_TEXT, 0, R.string.copy_message_text).setOnMenuItemClickListener(l); menu.add(0, MENU_COPY_MESSAGE_TO_SIM, 0, R.string.move_message_to_sim_text) .setOnMenuItemClickListener(l); } menu.add(0, MENU_VIEW_MESSAGE_DETAILS, 0, R.string.view_message_details).setOnMenuItemClickListener(l); menu.add(0, MENU_DELETE_MESSAGE, 0, R.string.delete_message).setOnMenuItemClickListener(l); if (msgItem.mDeliveryStatus != MessageItem.DeliveryStatus.NONE || msgItem.mReadReport) { menu.add(0, MENU_DELIVERY_REPORT, 0, R.string.view_delivery_report).setOnMenuItemClickListener(l); } } }; private void editMessageItem(MessageItem msgItem) { if ("sms".equals(msgItem.mType)) { editSmsMessageItem(msgItem); } else { editMmsMessageItem(msgItem); } if (msgItem.isFailedMessage() && mMsgListAdapter.getCount() <= 1) { // For messages with bad addresses, let the user re-edit the recipients. initRecipientsEditor(); } } private void editSmsMessageItem(MessageItem msgItem) { // When the message being edited is the only message in the conversation, the delete // below does something subtle. The trigger "delete_obsolete_threads_pdu" sees that a // thread contains no messages and silently deletes the thread. Meanwhile, the mConversation // object still holds onto the old thread_id and code thinks there's a backing thread in // the DB when it really has been deleted. Here we try and notice that situation and // clear out the thread_id. Later on, when Conversation.ensureThreadId() is called, we'll // create a new thread if necessary. synchronized (mConversation) { if (mConversation.getMessageCount() <= 1) { mConversation.clearThreadId(); } } // Delete the old undelivered SMS and load its content. Uri uri = ContentUris.withAppendedId(Sms.CONTENT_URI, msgItem.mMsgId); //fixed bug17720 start if (outboxEditMsgFlg) { SqliteWrapper.delete(ComposeMessageActivity.this, mContentResolver, uri, null, null); } else { /*fixed CR<NEWMS00147583> by luning at 2011.12.07 begin*/ if (msgItem.isFailedMessage()) { ContentValues values = new ContentValues(1); values.put(Sms.TYPE, Sms.MESSAGE_TYPE_DRAFT); SqliteWrapper.update(ComposeMessageActivity.this, mContentResolver, uri, values, null, null); } /*fixed CR<NEWMS00147583> by luning at 2011.12.07 end*/ else { SqliteWrapper.delete(ComposeMessageActivity.this, mContentResolver, uri, null, null); } } //fixed bug17720 end mWorkingMessage.setText(msgItem.mBody); } private void editMmsMessageItem(MessageItem msgItem) { // Discard the current message in progress. mWorkingMessage.discard(); // Load the selected message in as the working message. mWorkingMessage = WorkingMessage.load(this, msgItem.mMessageUri, false); mWorkingMessage.setConversation(mConversation); mAttachmentEditor.update(mWorkingMessage); drawTopPanel(); // WorkingMessage.load() above only loads the slideshow. Set the // subject here because we already know what it is and avoid doing // another DB lookup in load() just to get it. mWorkingMessage.setSubject(msgItem.mSubject, false); if (mWorkingMessage.hasSubject()) { showSubjectEditor(true); } } public void copyToClipboard(String str) { ClipboardManager clip = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); clip.setText(str); } private void resendMessage(MessageItem msgItem) { Uri uri; if ("sms".equals(msgItem.mType)) { uri = Sms.CONTENT_URI; final Uri resendUri = ContentUris.withAppendedId(uri, msgItem.mMsgId); final ContentValues values = new ContentValues(1); values.put(Sms.TYPE, Sms.MESSAGE_TYPE_QUEUED); values.put(Sms.DATE, System.currentTimeMillis()); getContentResolver().update(resendUri, values, null, null); this.getApplicationContext().sendBroadcast(new Intent(SmsReceiverService.ACTION_SEND_MESSAGE, null, this.getApplicationContext(), SmsReceiver.class)); } else { // Now update the pending_msgs table with an error for that new item. ContentValues values = new ContentValues(4); values.put(PendingMessages.ERROR_TYPE, MmsSms.NO_ERROR); values.put(PendingMessages.ERROR_CODE, 0); values.put(PendingMessages.RETRY_INDEX, 0); values.put(PendingMessages.DUE_TIME, 0); long msgId = ContentUris.parseId(msgItem.mMessageUri); SqliteWrapper.update(this, mContentResolver, PendingMessages.CONTENT_URI, values, PendingMessages._ID + "=" + msgId, null); // Start MMS transaction service SendingProgressTokenManager.put(ContentUris.parseId(msgItem.mMessageUri), mConversation.ensureThreadId()); this.startService(new Intent(this, TransactionService.class)); } } private void resendMessage(MessageItem msgItem, int phoneId) { Uri uri; if ("sms".equals(msgItem.mType)) { uri = Sms.CONTENT_URI; final Uri resendUri = ContentUris.withAppendedId(uri, msgItem.mMsgId); final ContentValues values = new ContentValues(1); values.put(Sms.TYPE, Sms.MESSAGE_TYPE_QUEUED); values.put(Sms.DATE, System.currentTimeMillis()); getContentResolver().update(resendUri, values, null, null); this.getApplicationContext().sendBroadcast(new Intent(SmsReceiverService.ACTION_SEND_MESSAGE, null, this.getApplicationContext(), SmsReceiver.class)); } else { // Now update the pending_msgs table with an error for that new item. ContentValues values = new ContentValues(4); values.put(PendingMessages.ERROR_TYPE, MmsSms.NO_ERROR); values.put(PendingMessages.ERROR_CODE, 0); values.put(PendingMessages.RETRY_INDEX, 0); values.put(PendingMessages.DUE_TIME, 0); long msgId = ContentUris.parseId(msgItem.mMessageUri); SqliteWrapper.update(this, mContentResolver, PendingMessages.CONTENT_URI, values, PendingMessages.MSG_ID + "=" + msgId, null); // Start MMS transaction service SendingProgressTokenManager.put(ContentUris.parseId(msgItem.mMessageUri), mConversation.ensureThreadId()); //this.startService(new Intent(this, TransactionService.class)); if (MessageUtils.isMSMS) { Log.i(TAG, "mPhoneId is" + phoneId); this.startService(new Intent(this, TransactionServiceHelper.getTransactionServiceClass(phoneId))); } else { this.startService(new Intent(this, TransactionService.class)); } } } private void forwardMessage(MessageItem msgItem) { Intent intent = createIntent(this, 0); intent.putExtra("exit_on_sent", true); intent.putExtra("forwarded_message", true); intent.putExtra("sender_number", msgItem.mAddress); if (msgItem.mType.equals("sms")) { intent.putExtra("sms_body", msgItem.mBody); } else { SendReq sendReq = new SendReq(); String subject = getString(R.string.forward_prefix); if (msgItem.mSubject != null) { subject += msgItem.mSubject; } sendReq.setSubject(new EncodedStringValue(subject)); sendReq.setBody(msgItem.mSlideshow.makeCopy(ComposeMessageActivity.this)); Uri uri = null; try { PduPersister persister = PduPersister.getPduPersister(this); // Copy the parts of the message here. uri = persister.persist(sendReq, Mms.Draft.CONTENT_URI); } catch (MmsException e) { Log.e(TAG, "Failed to copy message: " + msgItem.mMessageUri, e); Toast.makeText(ComposeMessageActivity.this, R.string.cannot_save_message, Toast.LENGTH_SHORT) .show(); return; } intent.putExtra("msg_uri", uri); intent.putExtra("subject", subject); } // ForwardMessageActivity is simply an alias in the manifest for ComposeMessageActivity. // We have to make an alias because ComposeMessageActivity launch flags specify // singleTop. When we forward a message, we want to start a separate ComposeMessageActivity. // The only way to do that is to override the singleTop flag, which is impossible to do // in code. By creating an alias to the activity, without the singleTop flag, we can // launch a separate ComposeMessageActivity to edit the forward message. intent.setClassName(this, "com.android.mms.ui.ForwardMessageActivity"); startActivity(intent); } private void copyMessageToSim(MessageItem msgItem, int phoneId) { boolean result = false; boolean isOutgoing = false; String timeString = null; String bcdtimeString = null; if (msgItem.mType.equals("sms")) { SmsManager smsManager = SmsManager.getDefault(phoneId); ArrayList<String> messages = null; messages = smsManager.divideMessage(msgItem.mBody); //boolean isOutgoing = msgItem.isOutgoingMessage(); if (msgItem.getBoxId() == Sms.MESSAGE_TYPE_SENT) { isOutgoing = true; } Log.d(TAG, "[cmgw]isOutgoing =" + isOutgoing); //if (!isOutgoing) { Time t = new Time(); t.set(msgItem.mDate); timeString = t.format("%g%m%d%H%M%S"); Log.d(TAG, "[cmgw]timeString =" + timeString); // byte[] timebcd = PhoneNumberUtils.numberToCalledPartyBCD(timeString); // Log.d(TAG, "[cmgw]bcdlen ="+timebcd.length+" timelen =" + timeString.length()); // if (timebcd.length > timeString.length()/2) { // int dataIndex = 1; // byte[] data = new byte[timebcd.length - dataIndex]; // System.arraycopy(timebcd, dataIndex, data, 0, data.length); // bcdtimeString = IccUtils.bytesToHexString(data) + "00"; // } else { // bcdtimeString = IccUtils.bytesToHexString(timebcd) + "00"; // } Log.d(TAG, "[cmgw]bcd timeString =" + bcdtimeString); //} byte[] timebcd = MessageUtils.GetSctsTime(t); bcdtimeString = IccUtils.bytesToHexString(timebcd); Log.d(TAG, "[cmgw]bcd timeString =" + bcdtimeString); result = smsManager.saveMultipartTextMessage(msgItem.mAddress, messages, isOutgoing, bcdtimeString); Log.d(TAG, "[cmgw]save result =" + result); int resId = result ? R.string.copy_message_result_success : R.string.copy_message_result_faile; Toast.makeText(ComposeMessageActivity.this, resId, Toast.LENGTH_SHORT).show(); } else { Log.d(TAG, "[cmgw]Not a sms, do nothing!!"); } } /** * Context menu handlers for the message list view. */ private final class MsgListMenuClickListener implements MenuItem.OnMenuItemClickListener { public boolean onMenuItemClick(MenuItem item) { if (!isCursorValid()) { return false; } Cursor cursor = mMsgListAdapter.getCursor(); String type = cursor.getString(COLUMN_MSG_TYPE); int phoneId = cursor.getInt(COLUMN_SMS_PHONE_ID); long msgId = cursor.getLong(COLUMN_ID); MessageItem msgItem = getMessageItem(type, msgId, true); Log.i(TAG, "onMenuItemClick phoneId is" + phoneId); if (msgItem == null) { return false; } switch (item.getItemId()) { case MENU_EDIT_MESSAGE: outboxEditMsgFlg = true; editMessageItem(msgItem); drawBottomPanel(); return true; case MENU_COPY_MESSAGE_TEXT: copyToClipboard(msgItem.mBody); return true; case MENU_COPY_MESSAGE_TO_SIM: if (!mSmsReady[phoneId]) {/* fixed CR<NEWMS00137946> by luning at 2011.11.15*/ Toast.makeText(ComposeMessageActivity.this, R.string.sim_no_ready, Toast.LENGTH_LONG).show(); } else if (MessageUtils.isSimMemFull(phoneId)) { Log.d(TAG, "sim memory full"); Toast.makeText(ComposeMessageActivity.this, R.string.sim_full_title, Toast.LENGTH_SHORT).show(); } else { Log.d(TAG, "Do copy message to sim"); Bundle bun = new Bundle(); bun.putLong("msgId", msgId); bun.putString("type", type); bun.putInt("PhoneId", phoneId); Message msg = new Message(); msg.setData(bun); msg.what = MENU_COPY_MESSAGE_TO_SIM; if (mMessageOperationHandler != null) { mMessageOperationHandler.sendMessage(msg); } } return true; case MENU_FORWARD_MESSAGE: forwardMessage(msgItem); return true; case MENU_RESEND_MESSAGE: resendMessage(msgItem, phoneId); return true; case MENU_VIEW_SLIDESHOW: MessageUtils.viewMmsMessageAttachment(ComposeMessageActivity.this, ContentUris.withAppendedId(Mms.CONTENT_URI, msgId), null); return true; case MENU_VIEW_MESSAGE_DETAILS: { String messageDetails = MessageUtils.getMessageDetails(ComposeMessageActivity.this, cursor, msgItem.mMessageSize); new AlertDialog.Builder(ComposeMessageActivity.this).setTitle(R.string.message_details_title) .setMessage(messageDetails).setPositiveButton(android.R.string.ok, null).setCancelable(true) .show(); return true; } case MENU_DELETE_MESSAGE: { DeleteMessageListener l = new DeleteMessageListener(msgItem.mMessageUri, msgItem.mLocked); confirmDeleteDialog(l, msgItem.mLocked); return true; } case MENU_DELIVERY_REPORT: showDeliveryReport(msgId, type); return true; case MENU_COPY_TO_SDCARD: { String resStr; if (copyMedia(msgId)) { String dir = Environment.getExternalStorageDirectory() + "/" + Environment.DIRECTORY_DOWNLOADS + "/"; resStr = getString(R.string.copy_to_sdcard_success, dir); } else { resStr = getString(R.string.copy_to_sdcard_fail); } Toast.makeText(ComposeMessageActivity.this, resStr, Toast.LENGTH_SHORT).show(); return true; } case MENU_COPY_TO_DRM_PROVIDER: { int resId = getDrmMimeSavedStringRsrc(msgId, copyToDrmProvider(msgId)); Toast.makeText(ComposeMessageActivity.this, resId, Toast.LENGTH_SHORT).show(); return true; } case MENU_LOCK_MESSAGE: { lockMessage(msgItem, true); return true; } case MENU_UNLOCK_MESSAGE: { lockMessage(msgItem, false); return true; } //===== fixed CR<NEWMS00120677> by luning at 11-09-17 begin===== case MENU_SAVE_BOOKMARK: { Intent intent = item.getIntent(); if (null != intent) { ArrayList<String> webLinks = (ArrayList<String>) intent.getSerializableExtra("webLinks"); if (null != webLinks && webLinks.size() > 0) { final CharSequence[] items = new CharSequence[webLinks.size()]; webLinks.toArray(items); webLinks = null; new AlertDialog.Builder(ComposeMessageActivity.this) .setTitle(getString(R.string.save_to_bookmarks)) .setNegativeButton(getString(android.R.string.cancel), null) .setItems(items, new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Intent i = new Intent(ACTION_SAVE_BOOKMARK); i.putExtra("url", items[which]); i.putExtra("retainIcon", false); startActivity(i); } }).show(); } } return true; } //===== fixed CR<NEWMS00120677> by luning at 11-09-17 end===== case MENU_ADD_ADDRESS_TO_CONTACTS: { mAddContactIntent = item.getIntent(); ComposeMessageActivity.this.startActivityForResult(mAddContactIntent, REQUEST_CODE_ADD_CONTACT); return true; } case MENU_SEND_SMS: isLongPressSendFlg = true; return false; default: return false; } } } private void lockMessage(MessageItem msgItem, boolean locked) { Uri uri; if ("sms".equals(msgItem.mType)) { uri = Sms.CONTENT_URI; } else { uri = Mms.CONTENT_URI; } final Uri lockUri = ContentUris.withAppendedId(uri, msgItem.mMsgId); final ContentValues values = new ContentValues(1); values.put("locked", locked ? 1 : 0); new Thread(new Runnable() { public void run() { getContentResolver().update(lockUri, values, null, null); } }, "lockMessage").start(); } /** * Looks to see if there are any valid parts of the attachment that can be copied to a SD card. * @param msgId */ private boolean haveSomethingToCopyToSDCard(long msgId) { PduBody body = PduBodyCache.getPduBody(this, ContentUris.withAppendedId(Mms.CONTENT_URI, msgId)); if (body == null) { return false; } boolean result = false; int partNum = body.getPartsNum(); for (int i = 0; i < partNum; i++) { PduPart part = body.getPart(i); String type = new String(part.getContentType()); if (DEBUG || Log.isLoggable(LogTag.APP, Log.VERBOSE)) { log("[CMA] haveSomethingToCopyToSDCard: part[" + i + "] contentType=" + type); } if (ContentType.isImageType(type) || ContentType.isVideoType(type) || ContentType.isAudioType(type)) { result = true; break; } } return result; } /** * Looks to see if there are any drm'd parts of the attachment that can be copied to the * DrmProvider. Right now we only support saving audio (e.g. ringtones). * @param msgId */ private boolean haveSomethingToCopyToDrmProvider(long msgId) { String mimeType = getDrmMimeType(msgId); return isAudioMimeType(mimeType); } /** * Simple cache to prevent having to load the same PduBody again and again for the same uri. */ private static class PduBodyCache { private static PduBody mLastPduBody; private static Uri mLastUri; static public PduBody getPduBody(Context context, Uri contentUri) { if (contentUri.equals(mLastUri)) { return mLastPduBody; } try { mLastPduBody = SlideshowModel.getPduBody(context, contentUri); mLastUri = contentUri; } catch (MmsException e) { Log.e(TAG, e.getMessage(), e); return null; } return mLastPduBody; } }; /** * Copies media from an Mms to the DrmProvider * @param msgId */ private boolean copyToDrmProvider(long msgId) { boolean result = true; PduBody body = PduBodyCache.getPduBody(this, ContentUris.withAppendedId(Mms.CONTENT_URI, msgId)); if (body == null) { return false; } int partNum = body.getPartsNum(); for (int i = 0; i < partNum; i++) { PduPart part = body.getPart(i); String type = new String(part.getContentType()); if (ContentType.isDrmType(type)) { // All parts (but there's probably only a single one) have to be successful // for a valid result. result &= copyPartToDrmProvider(part); } } return result; } private String mimeTypeOfDrmPart(PduPart part) { Uri uri = part.getDataUri(); InputStream input = null; try { input = mContentResolver.openInputStream(uri); if (input instanceof FileInputStream) { FileInputStream fin = (FileInputStream) input; DrmRawContent content = new DrmRawContent(fin, fin.available(), DrmRawContent.DRM_MIMETYPE_MESSAGE_STRING); String mimeType = content.getContentType(); return mimeType; } } catch (IOException e) { // Ignore Log.e(TAG, "IOException caught while opening or reading stream", e); } catch (DrmException e) { Log.e(TAG, "DrmException caught ", e); } finally { if (null != input) { try { input.close(); } catch (IOException e) { // Ignore Log.e(TAG, "IOException caught while closing stream", e); } } } return null; } /** * Returns the type of the first drm'd pdu part. * @param msgId */ private String getDrmMimeType(long msgId) { PduBody body = PduBodyCache.getPduBody(this, ContentUris.withAppendedId(Mms.CONTENT_URI, msgId)); if (body == null) { return null; } int partNum = body.getPartsNum(); for (int i = 0; i < partNum; i++) { PduPart part = body.getPart(i); String type = new String(part.getContentType()); if (ContentType.isDrmType(type)) { return mimeTypeOfDrmPart(part); } } return null; } private int getDrmMimeMenuStringRsrc(long msgId) { String mimeType = getDrmMimeType(msgId); if (isAudioMimeType(mimeType)) { return R.string.save_ringtone; } return 0; } private int getDrmMimeSavedStringRsrc(long msgId, boolean success) { String mimeType = getDrmMimeType(msgId); if (isAudioMimeType(mimeType)) { return success ? R.string.saved_ringtone : R.string.saved_ringtone_fail; } return 0; } private boolean isAudioMimeType(String mimeType) { return mimeType != null && mimeType.startsWith("audio/"); } private boolean isImageMimeType(String mimeType) { return mimeType != null && mimeType.startsWith("image/"); } private boolean copyPartToDrmProvider(PduPart part) { Uri uri = part.getDataUri(); InputStream input = null; try { input = mContentResolver.openInputStream(uri); if (input instanceof FileInputStream) { FileInputStream fin = (FileInputStream) input; // Build a nice title byte[] location = part.getName(); if (location == null) { location = part.getFilename(); } if (location == null) { location = part.getContentLocation(); } // Depending on the location, there may be an // extension already on the name or not String title = new String(location); int index; if ((index = title.indexOf(".")) == -1) { String type = new String(part.getContentType()); } else { title = title.substring(0, index); } // transfer the file to the DRM content provider Intent item = DrmStore.addDrmFile(mContentResolver, fin, title); if (item == null) { Log.w(TAG, "unable to add file " + uri + " to DrmProvider"); return false; } } } catch (IOException e) { // Ignore Log.e(TAG, "IOException caught while opening or reading stream", e); return false; } finally { if (null != input) { try { input.close(); } catch (IOException e) { // Ignore Log.e(TAG, "IOException caught while closing stream", e); return false; } } } return true; } /** * Copies media from an Mms to the "download" directory on the SD card * @param msgId */ private boolean copyMedia(long msgId) { boolean result = true; PduBody body = PduBodyCache.getPduBody(this, ContentUris.withAppendedId(Mms.CONTENT_URI, msgId)); if (body == null) { return false; } int partNum = body.getPartsNum(); for (int i = 0; i < partNum; i++) { PduPart part = body.getPart(i); String type = new String(part.getContentType()); if (ContentType.isImageType(type) || ContentType.isVideoType(type) || ContentType.isAudioType(type)) { result &= copyPart(part, Long.toHexString(msgId)); // all parts have to be successful for a valid result. } } return result; } private boolean copyPart(PduPart part, String fallback) { Uri uri = part.getDataUri(); InputStream input = null; FileOutputStream fout = null; try { input = mContentResolver.openInputStream(uri); if (input instanceof FileInputStream) { FileInputStream fin = (FileInputStream) input; byte[] location = part.getName(); if (location == null) { location = part.getFilename(); } if (location == null) { location = part.getContentLocation(); } String fileName; if (location == null) { // Use fallback name. fileName = fallback; } else { fileName = new String(location); } // Depending on the location, there may be an // extension already on the name or not String dir = Environment.getExternalStorageDirectory() + "/" + Environment.DIRECTORY_DOWNLOADS + "/"; String extension; int index; if ((index = fileName.indexOf(".")) == -1) { String type = new String(part.getContentType()); extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(type); } else { extension = fileName.substring(index + 1, fileName.length()); fileName = fileName.substring(0, index); } File file = getUniqueDestination(dir + fileName, extension); // make sure the path is valid and directories created for this file. File parentFile = file.getParentFile(); if (!parentFile.exists() && !parentFile.mkdirs()) { Log.e(TAG, "[MMS] copyPart: mkdirs for " + parentFile.getPath() + " failed!"); return false; } fout = new FileOutputStream(file); byte[] buffer = new byte[8000]; int size = 0; while ((size = fin.read(buffer)) != -1) { fout.write(buffer, 0, size); } // Notify other applications listening to scanner events // that a media file has been added to the sd card sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(file))); } } catch (IOException e) { // Ignore Log.e(TAG, "IOException caught while opening or reading stream", e); return false; } finally { if (null != input) { try { input.close(); } catch (IOException e) { // Ignore Log.e(TAG, "IOException caught while closing stream", e); return false; } } if (null != fout) { try { fout.close(); } catch (IOException e) { // Ignore Log.e(TAG, "IOException caught while closing stream", e); return false; } } } return true; } private File getUniqueDestination(String base, String extension) { File file = new File(base + "." + extension); for (int i = 2; file.exists(); i++) { file = new File(base + "_" + i + "." + extension); } return file; } private void showDeliveryReport(long messageId, String type) { Intent intent = new Intent(this, DeliveryReportActivity.class); intent.putExtra("message_id", messageId); intent.putExtra("message_type", type); startActivity(intent); } private IntentFilter mHttpProgressFilter = new IntentFilter(PROGRESS_STATUS_ACTION); private BroadcastReceiver mHttpProgressReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (PROGRESS_STATUS_ACTION.equals(intent.getAction())) { long token = intent.getLongExtra("token", SendingProgressTokenManager.NO_TOKEN); if (token != mConversation.getThreadId()) { return; } int progress = intent.getIntExtra("progress", 0); switch (progress) { case PROGRESS_START: setProgressBarVisibility(true); break; case PROGRESS_ABORT: case PROGRESS_COMPLETE: setProgressBarVisibility(false); break; default: setProgress(100 * progress); } } } }; private static ContactList sEmptyContactList; private ContactList getRecipients() { // If the recipients editor is visible, the conversation has // not really officially 'started' yet. Recipients will be set // on the conversation once it has been saved or sent. In the // meantime, let anyone who needs the recipient list think it // is empty rather than giving them a stale one. if (isRecipientsEditorVisible()) { if (sEmptyContactList == null) { sEmptyContactList = new ContactList(); } return sEmptyContactList; } return mConversation.getRecipients(); } private void updateTitle(ContactList list) { String s; switch (list.size()) { case 0: { String recipient = ""; if (mRecipientsEditor != null && mRecipientsEditor.getText() != null) { recipient = mRecipientsEditor.getText().toString(); } s = recipient; break; } case 1: { s = list.get(0).getNameAndNumber(); break; } default: { // Handle multiple recipients s = list.formatNames(", "); break; } } //yeezone:jinwei if (FeatureSwitch.COMPOSE_MESSAGE_TIP_SUPPORT) { mTitleLeft.setText(s); } else { getWindow().setTitle(s); } mDebugRecipients = list.serialize(); // getWindow().setTitle(s); } // Get the recipients editor ready to be displayed onscreen. private void initRecipientsEditor() { if (isRecipientsEditorVisible()) { return; } // Must grab the recipients before the view is made visible because getRecipients() // returns empty recipients when the editor is visible. ContactList recipients = getRecipients(); if (null == mRecipientsEditor) {/* add for HUAWEI bug by luning at 2011.12.27 */ ViewStub stub = (ViewStub) findViewById(R.id.recipients_editor_stub); if (stub != null) { mRecipientsEditor = (RecipientsEditor) stub.inflate(); } else { LinearLayout parentLayout = (LinearLayout) findViewById(R.id.recipients_send); if (parentLayout == null) { Log.i(TAG, "LinearLayout parentLayout = (LinearLayout) findViewById(R.id.recipients_send); Finish"); finish(); } stub = new ViewStub(this, R.layout.recipients_editor); stub.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, 1.0f)); parentLayout.addView(stub, 0); mRecipientsEditor = (RecipientsEditor) stub.inflate(); } } mRecipientsEditor.setAdapter(new RecipientsAdapter(this)); // for fix bug 14109 start. //mRecipientsEditor.populate(recipients); if ((DRAFTS.equals(boxType) || OUTBOX.equals(boxType) || SENT.equals(boxType)) && (MessageBoxActivity.mBoxMsgRecipients != null)) { mRecipientsEditor.populate(MessageBoxActivity.mBoxMsgRecipients); } else { mRecipientsEditor.populate(recipients); } // for fix bug 14109 end. mRecipientsEditor.setOnCreateContextMenuListener(mRecipientsMenuCreateListener); mRecipientsEditor.addTextChangedListener(mRecipientsWatcher); mRecipientsEditor.setFilters(new InputFilter[] { new InputFilter.LengthFilter(RECIPIENTS_MAX_LENGTH) }); mRecipientsEditor.setOnItemClickListener(new AdapterView.OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // After the user selects an item in the pop-up contacts list, move the // focus to the text editor if there is only one recipient. This helps // the common case of selecting one recipient and then typing a message, // but avoids annoying a user who is trying to add five recipients and // keeps having focus stolen away. if (mRecipientsEditor.getRecipientCount() == 1 && mTextEditor != null) { // if we're in extract mode then don't request focus final InputMethodManager inputManager = (InputMethodManager) getSystemService( Context.INPUT_METHOD_SERVICE); if (inputManager == null || (inputManager != null && !inputManager.isFullscreenMode())) { mTextEditor.requestFocus(); } } } }); mRecipientsEditor.setOnFocusChangeListener(new View.OnFocusChangeListener() { public void onFocusChange(View v, boolean hasFocus) { if (!hasFocus) { RecipientsEditor editor = (RecipientsEditor) v; ContactList contacts = editor.constructContactsFromInput(); updateTitle(contacts); } } }); /* modify for HUAWEI bug by luning at 2011.12.27 begin */ mRecipientsEditor.setVisibility(View.VISIBLE); if (null != mContactsSelectButton) { mContactsSelectButton.setVisibility(View.VISIBLE); } /* modify for HUAWEI bug by luning at 2011.12.27 end */ if (mTopPanel != null) { mTopPanel.setVisibility(View.VISIBLE); } } //========================================================== // Activity methods //========================================================== public static boolean cancelFailedToDeliverNotification(Intent intent, Context context) { if (MessagingNotification.isFailedToDeliver(intent)) { // Cancel any failed message notifications MessagingNotification.cancelNotification(context, MessagingNotification.MESSAGE_FAILED_NOTIFICATION_ID); return true; } return false; } public static boolean cancelFailedDownloadNotification(Intent intent, Context context) { if (MessagingNotification.isFailedToDownload(intent)) { // Cancel any failed download notifications MessagingNotification.cancelNotification(context, MessagingNotification.DOWNLOAD_FAILED_NOTIFICATION_ID); return true; } return false; } @Override protected void onCreate(Bundle savedInstanceState) { System.gc(); super.onCreate(savedInstanceState); //yeezone:jinwei add custom title mContextView = (LinearLayout) ((LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE)) .inflate(R.layout.compose_message_activity, null); if (FeatureSwitch.COMPOSE_MESSAGE_TIP_SUPPORT) { requestWindowFeature(Window.FEATURE_CUSTOM_TITLE); // setContentView(R.layout.compose_message_activity); setContentView(mContextView); getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.customize_title_compose_message); } else { // setContentView(R.layout.compose_message_activity); setContentView(mContextView); } mSimChooserDialg = new SimChooserDialog(this); mTelephonyManager = (TelephonyManager) getApplicationContext().getSystemService(Context.TELEPHONY_SERVICE); setProgressBarVisibility(false); getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE | WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN); // Initialize members for UI elements. initResourceRefs(); mContentResolver = getContentResolver(); mBackgroundQueryHandler = new BackgroundQueryHandler(mContentResolver); initialize(savedInstanceState, 0); if (TRACE) { android.os.Debug.startMethodTracing("compose"); } } private void showSubjectEditor(boolean show) { if (DEBUG || Log.isLoggable(LogTag.APP, Log.VERBOSE)) { log("" + show); } if (mSubjectTextEditor == null) { // Don't bother to initialize the subject editor if // we're just going to hide it. if (show == false) { return; } mSubjectTextEditor = (EditText) findViewById(R.id.subject); } mSubjectTextEditor.setOnKeyListener(show ? mSubjectKeyListener : null); synchronized (mSubjectTextEditor) { if (show) { mSubjectTextEditor.addTextChangedListener(mSubjectEditorWatcher); } else { mSubjectTextEditor.removeTextChangedListener(mSubjectEditorWatcher); } if (mWorkingMessage != null && mWorkingMessage.hasSubject()) { mSubjectTextEditor.setText(mWorkingMessage.getSubject()); } else { mSubjectTextEditor.setText(""); } } mSubjectTextEditor.setVisibility(show ? View.VISIBLE : View.GONE); hideOrShowTopPanel(); } private void hideOrShowTopPanel() { boolean anySubViewsVisible = (isSubjectEditorVisible() || isRecipientsEditorVisible()); // === modify by luning at 11-09-02 begin === if (isRecipientsEditorVisible()) { mContactsSelectButton.setVisibility(View.VISIBLE); } else { mContactsSelectButton.setVisibility(View.GONE); } // === modify by luning at 11-09-02 end === if (SENT.equals(boxType) || OUTBOX.equals(boxType)) { mTopPanel.setVisibility(View.GONE); } else { mTopPanel.setVisibility(anySubViewsVisible ? View.VISIBLE : View.GONE); } } public void initialize(Bundle savedInstanceState, long originalThreadId) { Intent intent = getIntent(); Bundle bundle = intent.getExtras(); if (bundle != null) { boxmsgFlg = bundle.getString("boxmsgFlg"); boxmsgThreadId = bundle.getString("boxmsgThreadId"); boxmsgMsgId = bundle.getString("boxmsgMsgId"); boxType = bundle.getString("boxType"); } else { boxmsgFlg = "false"; boxmsgThreadId = originalThreadId + ""; boxType = ""; } // Create a new empty working message. mWorkingMessage = WorkingMessage.createEmpty(this); // Read parameters or previously saved state of this activity. This will load a new // mConversation initActivityState(savedInstanceState, intent, bundle); if (LogTag.SEVERE_WARNING && originalThreadId != 0 && originalThreadId == mConversation.getThreadId()) { LogTag.warnPossibleRecipientMismatch( "ComposeMessageActivity.initialize: " + " threadId didn't change from: " + originalThreadId, this); } log("savedInstanceState = " + savedInstanceState + " intent = " + intent + " mConversation = " + mConversation); if (cancelFailedToDeliverNotification(getIntent(), this)) { // Show a pop-up dialog to inform user the message was // failed to deliver. undeliveredMessageDialog(getMessageDate(null)); } cancelFailedDownloadNotification(getIntent(), this); // Set up the message history ListAdapter initMessageList(); // Show the recipients editor if we don't have a valid thread. Hide it otherwise. if (mConversation.getThreadId() <= 0) { // Hide the recipients editor so the call to initRecipientsEditor won't get // short-circuited. hideRecipientEditor(); initRecipientsEditor(); // Bring up the softkeyboard so the user can immediately enter recipients. This // call won't do anything on devices with a hard keyboard. getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE | WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); } else { hideRecipientEditor(); } // Load the draft for this thread, if we aren't already handling // existing data, such as a shared picture or forwarded message. boolean isForwardedMessage = false; if (!handleSendIntent(intent)) { isForwardedMessage = handleForwardedMessage(); if (!isForwardedMessage) { loadDraft(); } } // Let the working message know what conversation it belongs to mWorkingMessage.setConversation(mConversation); updateSendButtonState(); drawTopPanel(); drawBottomPanel(); mAttachmentEditor.update(mWorkingMessage); Configuration config = getResources().getConfiguration(); mIsKeyboardOpen = config.keyboardHidden == KEYBOARDHIDDEN_NO; mIsLandscape = config.orientation == Configuration.ORIENTATION_LANDSCAPE; onKeyboardStateChanged(mIsKeyboardOpen); if (DEBUG || Log.isLoggable(LogTag.APP, Log.VERBOSE)) { log("update title, mConversation=" + mConversation.toString()); } updateTitle(mConversation.getRecipients()); if (isForwardedMessage && isRecipientsEditorVisible()) { // The user is forwarding the message to someone. Put the focus on the // recipient editor rather than in the message editor. mRecipientsEditor.requestFocus(); } } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); setIntent(intent); Conversation conversation = null; mSentMessage = false; notificationFlg = true; // If we have been passed a thread_id, use that to find our // conversation. // Note that originalThreadId might be zero but if this is a draft and we save the // draft, ensureThreadId gets called async from WorkingMessage.asyncUpdateDraftSmsMessage // the thread will get a threadId behind the UI thread's back. //long originalThreadId = mConversation.getThreadId(); Bundle bundle = intent.getExtras(); if (bundle != null) { boxmsgThreadId = bundle.getString("boxmsgThreadId"); } long threadId = intent.getLongExtra("thread_id", 0); Uri intentUri = intent.getData(); boolean sameThread = false; if (threadId > 0 && !"true".equals(boxmsgFlg)) { conversation = Conversation.get(this, threadId, false); } else { if (mConversation.getThreadId() == 0) { // We've got a draft. See if the new intent's recipient is the same as // the draft's recipient. First make sure the working recipients are synched // to the conversation. mWorkingMessage.syncWorkingRecipients(); sameThread = mConversation.sameRecipient(intentUri); } if (!sameThread) { // Otherwise, try to get a conversation based on the // data URI passed to our intent. conversation = Conversation.get(this, intentUri, false); } } if (LogTag.VERBOSE || DEBUG || Log.isLoggable(LogTag.APP, Log.VERBOSE)) { log("data=" + intentUri + ", thread_id extra is " + threadId + ", new conversation=" + conversation + ", mConversation=" + mConversation); } if (conversation != null) { // Don't let any markAsRead DB updates occur before we've loaded the messages for // the thread. conversation.blockMarkAsRead(true); // this is probably paranoia to compare both thread_ids and recipient lists, // but we want to make double sure because this is a last minute fix for Froyo // and the previous code checked thread ids only. // (we cannot just compare thread ids because there is a case where mConversation // has a stale/obsolete thread id (=1) that could collide against the new thread_id(=1), // even though the recipient lists are different) sameThread = (conversation.getThreadId() == mConversation.getThreadId() && conversation.equals(mConversation)); } if (sameThread && (!"true".equals(boxmsgFlg))) { log("same conversation"); } else { if (LogTag.VERBOSE || DEBUG || Log.isLoggable(LogTag.APP, Log.VERBOSE)) { log("different conversation"); } saveDraft(); // if we've got a draft, save it first long originalThreadId = conversation.getThreadId(); if (mMsgListAdapter != null) { mMsgListAdapter = null; } initialize(null, originalThreadId); loadMessageContent(); } } @Override protected void onRestart() { super.onRestart(); if (mWorkingMessage.isDiscarded()) { // If the message isn't worth saving, don't resurrect it. Doing so can lead to // a situation where a new incoming message gets the old thread id of the discarded // draft. This activity can end up displaying the recipients of the old message with // the contents of the new message. Recognize that dangerous situation and bail out // to the ConversationList where the user can enter this in a clean manner. if (mWorkingMessage.isWorthSaving()) { mWorkingMessage.unDiscard(); // it was discarded in onStop(). } else if (isRecipientsEditorVisible()) { //for bug 17097 --start--- Log.i(TAG, "onRestart: don't goToConversationList"); //goToConversationList(); //for bug 17097 --end--- } else { loadDraft(); mWorkingMessage.setConversation(mConversation); mAttachmentEditor.update(mWorkingMessage); } } } @Override protected void onStart() { super.onStart(); mConversation.blockMarkAsRead(true); initFocus(); // Register a BroadcastReceiver to listen on HTTP I/O process. registerReceiver(mHttpProgressReceiver, mHttpProgressFilter); loadMessageContent(); // Update the fasttrack info in case any of the recipients' contact info changed // while we were paused. This can happen, for example, if a user changes or adds // an avatar associated with a contact. mWorkingMessage.syncWorkingRecipients(); if (DEBUG || Log.isLoggable(LogTag.APP, Log.VERBOSE)) { log("update title, mConversation=" + mConversation.toString()); } updateTitle(mConversation.getRecipients()); // Listen for broadcast intents that indicate the SMS is ready IntentFilter filter = new IntentFilter(); if (MessageUtils.isMSMS) { filter.addAction(PhoneFactory.getAction(TelephonyIntents.ACTION_IS_SIM_SMS_READY, 0)); filter.addAction(PhoneFactory.getAction(TelephonyIntents.ACTION_IS_SIM_SMS_READY, 1)); } else { filter.addAction(TelephonyIntents.ACTION_IS_SIM_SMS_READY); } filter.addAction("sendMmsReadReport"); registerReceiver(mReceiver, filter); } public void loadMessageContent() { startMsgListQuery(); updateSendFailedNotification(); drawBottomPanel(); } private void updateSendFailedNotification() { final long threadId = mConversation.getThreadId(); if (threadId <= 0) return; // updateSendFailedNotificationForThread makes a database call, so do the work off // of the ui thread. new Thread(new Runnable() { public void run() { MessagingNotification.updateSendFailedNotificationForThread(ComposeMessageActivity.this, threadId); } }, "updateSendFailedNotification").start(); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putString("recipients", getRecipients().serialize()); mWorkingMessage.writeStateToBundle(outState); if (mExitOnSent) { outState.putBoolean("exit_on_sent", mExitOnSent); } } @Override protected void onResume() { super.onResume(); // OLD: get notified of presence updates to update the titlebar. // NEW: we are using ContactHeaderWidget which displays presence, but updating presence // there is out of our control. //Contact.startPresenceObserver(); addRecipientsListeners(); if (DEBUG || Log.isLoggable(LogTag.APP, Log.VERBOSE)) { log("update title, mConversation=" + mConversation.toString()); } // There seems to be a bug in the framework such that setting the title // here gets overwritten to the original title. Do this delayed as a // workaround. mMessageListItemHandler.postDelayed(new Runnable() { public void run() { //ContactList recipients = isRecipientsEditorVisible() ? //mRecipientsEditor.constructContactsFromInput() : getRecipients(); /*-------------------------by lai----------------------------*/ ContactList recipients; if (isRecipientsEditorVisible()) { recipients = mRecipientsEditor.constructContactsFromInput(); } else { recipients = getRecipients(); String[] PhoneNums = recipients.getNumbers(); mPhoneNumForMms = PhoneNums[PhoneNums.length - 1]; } /*-------------------------by lai----------------------------*/ updateTitle(recipients); } }, 100); //yeezone:jinwei if (FeatureSwitch.PHONE_REJECT_AUTO_SENT_SUPPORT) { Bundle bundle = this.getIntent().getExtras(); if (bundle != null && bundle.getBoolean("auto_send")) confirmSendMessageIfNeeded(); } /*TDFAE00015859********************************/ Intent intent = getIntent(); int mAction = intent.getIntExtra("mAction", -1); if (mAction == 0) { resolveContacts(intent); } /*TDFAE00015859******************************/ } @Override protected void onPause() { super.onPause(); // OLD: stop getting notified of presence updates to update the titlebar. // NEW: we are using ContactHeaderWidget which displays presence, but updating presence // there is out of our control. //Contact.stopPresenceObserver(); if (!is_vcard_adding) { removeRecipientsListeners(); } if (mAttachmentTypeSelectorAdapter != null) { mAttachmentTypeSelectorAdapter.clear(); mAttachmentTypeSelectorAdapter = null; } if (mAttachmentDialogBuilder != null) { mAttachmentDialogBuilder.setAdapter(null, null); mAttachmentDialogBuilder = null; } if (mAttachmentDialog != null) { mAttachmentDialog.cancel(); mAttachmentDialog = null; } } @Override protected void onStop() { super.onStop(); if (!is_vcard_adding) { InputMethodManager imm = ((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE)); if (imm != null && ComposeMessageActivity.this.getCurrentFocus() != null) { imm.hideSoftInputFromWindow(ComposeMessageActivity.this.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); } if (mMsgListAdapter != null && mMsgListAdapter.getMessageItemCache() != null) { mMsgListAdapter.getMessageItemCache().clear(); } if (mMsgListAdapter != null && mMsgListAdapter.getAddressToMessageListItems() != null) { mMsgListAdapter.getAddressToMessageListItems().clear(); } // Allow any blocked calls to update the thread's read status. mConversation.blockMarkAsRead(false); if (mMsgListAdapter != null) { mMsgListAdapter.changeCursor(null); } if (DEBUG || Log.isLoggable(LogTag.APP, Log.VERBOSE)) { log("save draft"); } if (mRecipientsEditor != null && isRecipientsEditorVisible() && !mRecipientsEditor.hasValidRecipient(mWorkingMessage.requiresMms())) { return; } saveDraft(); // Cleanup the BroadcastReceiver. unregisterReceiver(mHttpProgressReceiver); } } /* fixed CR<NEWMS119944 NEWMS119757 NEWMS119755 NEWMS120030 NEWMS119256> by lino release memory */ private void destroy() { HashMap<String, HashSet<MessageListItem>> addToMessLI = mMsgListAdapter.getAddressToMessageListItems(); Iterator<String> it = addToMessLI.keySet().iterator(); HashSet<MessageListItem> hashSetMLI = null; MessageListItem mlt = null; MessageItem mi = null; BitmapDrawable bd = null; ImageModel imageModel = null; while (it.hasNext()) { hashSetMLI = addToMessLI.get(it.next()); Iterator<MessageListItem> i = hashSetMLI.iterator(); while (i.hasNext()) { mlt = i.next(); mlt.destroy(); mlt.removeAllViewsInLayout(); mlt = null; } hashSetMLI.clear(); hashSetMLI = null; } addToMessLI.clear(); addToMessLI = null; if (mMsgListAdapter != null && mMsgListAdapter.getMessageItemCache() != null) { mMsgListAdapter.getMessageItemCache().clear(); } if (mAttachmentDialogBuilder != null) { mAttachmentDialogBuilder.setAdapter(null, null); mAttachmentDialogBuilder = null; } if (mAttachmentDialog != null) { mAttachmentDialog.cancel(); mAttachmentDialog = null; } // if (mMsgListAdapter != null) { // LinkedHashMap<Long, MessageItem> msgItemCatch = mMsgListAdapter.getMessageItemCache(); // if (null != msgItemCatch) { // MessageItem msgItem = null; // Model model = null; // SlideModel slide = null; // // Iterator iterator = msgItemCatch.entrySet().iterator(); // while (iterator.hasNext()) { // Map.Entry entry = (Map.Entry) iterator.next(); // msgItem = (MessageItem) entry.getValue(); // if (msgItem != null) { // model = (SlideshowModel) msgItem.mSlideshow; // if (model != null) { // slide = ((SlideshowModel) model).get(0); // if (null != slide) { // if (slide.hasImage()) { // imageModel = slide.getImage(); // // Bitmap bitMap = imageModel.getBitmapCache();/* fixed CR<NEWMS00138991> by luning at 2011.11.10*/ //// Bitmap bitMap = imageModel.getBitmap(); // // if (bitMap != null && !bitMap.isRecycled()) { // Log.v("lino", "mMessageItemCatch---!bitMap.isRecycled()"); // bitMap.recycle(); // bitMap = null; // } // } // } // slide = null; // } // } // imageModel = null; // } // // msgItemCatch.clear(); // msgItemCatch = null; // } // } //===== fixed CR<NEWMS00127096,NEWMS00127018,NEWMS00126971,NEWMS00127071> by luning at 11-09-29 begin===== if (mCursor != null) { mCursor.close(); // mCursor = null; } mMsgListView.removeAllViewsInLayout(); mMsgListView.setAdapter(null); // mMsgListAdapter = null; if (mTopPanel != null) { ((LinearLayout) mTopPanel).removeAllViewsInLayout(); // mTopPanel = null; } if (mBottomPanel != null) { ((LinearLayout) mBottomPanel).removeAllViewsInLayout(); // mBottomPanel = null; } if (mTextEditor != null) { mTextEditor.setOnEditorActionListener(null); //for bugzilla 13981 //mTextEditor.addTextChangedListener(null); // mTextEditor = null; } // if(mTextCounter != null){ // mTextCounter = null; // } if (mSendButton != null) { mSendButton.setOnClickListener(null); // mSendButton = null; } if (mContactsSelectButton != null) { mContactsSelectButton.setOnClickListener(null); // mContactsSelectButton = null; } if (mSubjectTextEditor != null) { mSubjectTextEditor.setOnEditorActionListener(null); //for bugzilla 13981 //mSubjectTextEditor.addTextChangedListener(null); // mSubjectTextEditor = null; } if (mRecipientsEditor != null) { //for bugzilla 13981 //mRecipientsEditor.addTextChangedListener(null); // mRecipientsEditor = null; } mAttachmentEditor.destroy(); mAttachmentEditor.removeAllViewsInLayout(); // mAttachmentEditor = null; mContextView.removeAllViewsInLayout(); notificationFlg = false; // mContextView = null; // mWorkingMessage = null; // list = null; // mAttachmentEditorHandler = null; // mBackgroundQueryHandler = null; // mConversation = null; // mContentResolver = null; // mDataSetChangedListener = null; // mHttpProgressFilter = null; // mHttpProgressReceiver = null; // mTitleLeft = null; // mTitleRight = null; // mTextEditorWatcher = null; // mMessageListItemHandler = null; // mMsgListMenuCreateListener = null; // mMsgListView = null; //===== fixed CR<NEWMS00127096,NEWMS00127018,NEWMS00126971,NEWMS00127071> by luning at 11-09-29 end===== // if(!mCreate){ // ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE); // am.killBackgroundProcesses(getPackageName()); // } } @Override protected void onDestroy() { if (TRACE) { android.os.Debug.stopMethodTracing(); } // list.clear();/*delete for CR<NEWMS00135995> by luning at 11-11-04 */ destroy(); super.onDestroy(); System.gc(); unregisterReceiver(mReceiver); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); if (LOCAL_LOGV) { Log.v(TAG, "onConfigurationChanged: " + newConfig); } mIsKeyboardOpen = newConfig.keyboardHidden == KEYBOARDHIDDEN_NO; boolean isLandscape = newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE; if (mIsLandscape != isLandscape) { mIsLandscape = isLandscape; // Have to re-layout the attachment editor because we have different layouts // depending on whether we're portrait or landscape. mAttachmentEditor.update(mWorkingMessage); } onKeyboardStateChanged(mIsKeyboardOpen); } private void onKeyboardStateChanged(boolean isKeyboardOpen) { // If the keyboard is hidden, don't show focus highlights for // things that cannot receive input. if (isKeyboardOpen) { if (mRecipientsEditor != null) { mRecipientsEditor.setFocusableInTouchMode(true); } if (mSubjectTextEditor != null) { mSubjectTextEditor.setFocusableInTouchMode(true); } mTextEditor.setFocusableInTouchMode(true); mTextEditor.setHint(R.string.type_to_compose_text_enter_to_send); } else { if (mRecipientsEditor != null) { mRecipientsEditor.setFocusable(false); } if (mSubjectTextEditor != null) { mSubjectTextEditor.setFocusable(false); } mTextEditor.setFocusable(false); mTextEditor.setHint(R.string.open_keyboard_to_compose_message); } } @Override public void onUserInteraction() { checkPendingNotification(); } @Override public void onWindowFocusChanged(boolean hasFocus) { if (hasFocus) { checkPendingNotification(); } } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_DEL: if ((mMsgListAdapter != null) && mMsgListView.isFocused()) { Cursor cursor; try { cursor = (Cursor) mMsgListView.getSelectedItem(); } catch (ClassCastException e) { Log.e(TAG, "Unexpected ClassCastException.", e); return super.onKeyDown(keyCode, event); } if (cursor != null) { boolean locked = cursor.getInt(COLUMN_MMS_LOCKED) != 0; DeleteMessageListener l = new DeleteMessageListener(cursor.getLong(COLUMN_ID), cursor.getString(COLUMN_MSG_TYPE), locked); confirmDeleteDialog(l, locked); return true; } } break; case KeyEvent.KEYCODE_DPAD_CENTER: case KeyEvent.KEYCODE_ENTER: if (isPreparedForSending()) { confirmSendMessageIfNeeded(); return true; } break; case KeyEvent.KEYCODE_BACK: exitComposeMessageActivity(new Runnable() { public void run() { finish(); } }); return true; } return super.onKeyDown(keyCode, event); } private void exitComposeMessageActivity(final Runnable exit) { // If the message is empty, just quit -- finishing the // activity will cause an empty draft to be deleted. if (!mWorkingMessage.isWorthSaving()) { exit.run(); return; } // fix bug 10287&10572 if (isRecipientsEditorVisible() && !mRecipientsEditor.hasValidRecipient(mWorkingMessage.requiresMms())) { MessageUtils.showDiscardDraftConfirmDialog(this, new DiscardDraftListener()); return; } //saveDraft(); // fix bug 21561 if (mWorkingMessage.getWorkingRecipients() == null && mRecipientsEditor != null) { mWorkingMessage.setWorkingRecipients(mRecipientsEditor.getNumbers()); } mToastForDraftSave = true; exit.run(); } private void goToConversationList() { finish(); startActivity(new Intent(this, ConversationList.class)); } private void hideRecipientEditor() { if (mRecipientsEditor != null) { mRecipientsEditor.removeTextChangedListener(mRecipientsWatcher); mRecipientsEditor.setVisibility(View.GONE); hideOrShowTopPanel(); } } private boolean isRecipientsEditorVisible() { return (null != mRecipientsEditor) && (View.VISIBLE == mRecipientsEditor.getVisibility()); } private boolean isSubjectEditorVisible() { return (null != mSubjectTextEditor) && (View.VISIBLE == mSubjectTextEditor.getVisibility()); } private boolean composeIsWapush() { Cursor cursor = mMsgListAdapter.getCursor(); boolean isWapPush = false; if (cursor == null || cursor.getCount() == 0) { return false; } if (cursor != null) { if (cursor.moveToFirst()) { int threadId = cursor.getInt(MessageListAdapter.COLUMN_THREAD_ID); Cursor cursorWap = getContentResolver().query(Sms.Inbox.CONTENT_URI, new String[] { "_id" }, "wap_push=1 and thread_id = " + threadId, null, null); if (cursorWap != null && cursorWap.getCount() > 0) { isWapPush = true; } if (cursorWap != null) { cursorWap.close(); } } } return isWapPush; } public void onAttachmentChanged() { // Have to make sure we're on the UI thread. This function can be called off of the UI // thread when we're adding multi-attachments runOnUiThread(new Runnable() { public void run() { drawBottomPanel(); updateSendButtonState(); mAttachmentEditor.update(mWorkingMessage); } }); } public void onProtocolChanged(final boolean mms) { // Have to make sure we're on the UI thread. This function can be called off of the UI // thread when we're adding multi-attachments runOnUiThread(new Runnable() { public void run() { toastConvertInfo(mms); setSendButtonText(mms); } }); } private void setSendButtonText(boolean isMms) { Button sendButton = mSendButton; sendButton.setText(R.string.send); if (isMms) { // Create and append the "MMS" text in a smaller font than the "Send" text. sendButton.append("\n"); SpannableString spannable = new SpannableString(getString(R.string.mms)); int mmsTextSize = (int) (sendButton.getTextSize() * 0.75f); spannable.setSpan(new AbsoluteSizeSpan(mmsTextSize), 0, spannable.length(), 0); sendButton.append(spannable); //===== fixed CR<NEWMS00134916> by luning at 11-10-28 begin ===== // mTextCounter.setText(""); resetCounter(); //===== fixed CR<NEWMS00134916> by luning at 11-10-28 end ===== } else { reCalcSmsCounter(mTextEditor.getText()); } } Runnable mResetMessageRunnable = new Runnable() { public void run() { resetMessage(); } }; public void onPreMessageSent() { //resetMessage(); runOnUiThread(mResetMessageRunnable); } public void onMessageSent() { // If we already have messages in the list adapter, it // will be auto-requerying; don't thrash another query in. if (mMsgListAdapter.getCount() == 0) { startMsgListQuery(); long threadid = mConversation.getThreadId(); mConversation.loadFromThreadId(threadid, false); } } public void onMaxPendingMessagesReached() { saveDraft(); runOnUiThread(new Runnable() { public void run() { Toast.makeText(ComposeMessageActivity.this, R.string.too_many_unsent_mms, Toast.LENGTH_LONG).show(); } }); } public void onAttachmentError(final int error) { runOnUiThread(new Runnable() { public void run() { handleAddAttachmentError(error, R.string.type_picture); onMessageSent(); // now requery the list of messages } }); } // We don't want to show the "call" option unless there is only one // recipient and it's a phone number. private boolean isRecipientCallable() { ContactList recipients = getRecipients(); return (recipients.size() == 1 && !recipients.containsEmail()); } public static Intent getVPIntent(Intent intent) { return intent.putExtra(EXTRA_IS_VIDEOCALL, true); } private void dialRecipient() { String number = getRecipients().get(0).getNumber(); Intent dialIntent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + number)); startActivity(dialIntent); } private void videodialRecipient() { String number = getRecipients().get(0).getNumber(); Intent dialIntent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + number)); startActivity(getVPIntent(dialIntent)); } @Override public boolean onPrepareOptionsMenu(Menu menu) { menu.clear(); if (isRecipientCallable() && !composeIsWapush()) { menu.add(0, MENU_CALL_RECIPIENT, 0, R.string.menu_call).setIcon(R.drawable.ic_menu_call); if (TelephonyManager.MODEM_TYPE_TDSCDMA == TelephonyManager.getDefault().getModemType() && SystemProperties.getBoolean("ro.device.support.vt", true)) { menu.add(0, MENU_VIDEOCALL_RECIPIENT, 0, R.string.menu_videocall).setIcon(R.drawable.ic_menu_call); } } // Only add the "View contact" menu item when there's a single recipient and that // recipient is someone in contacts. ContactList recipients = getRecipients(); if (recipients.size() == 1 && recipients.get(0).existsInDatabase()) { menu.add(0, MENU_VIEW_CONTACT, 0, R.string.menu_view_contact).setIcon(R.drawable.ic_menu_contact); } if (MmsConfig.getMmsEnabled()) { if (!isSubjectEditorVisible() && !SENT.equals(boxType) && (!OUTBOX.equals(boxType) || outboxEditMsgFlg)) { menu.add(0, MENU_ADD_SUBJECT, 0, R.string.add_subject).setIcon(R.drawable.ic_menu_edit); } // ======fixed CR<NEWMS00110179> by luning at 11-08-12 begin====== // if (!mWorkingMessage.hasAttachment()) { if (!SENT.equals(boxType) && (!OUTBOX.equals(boxType) || outboxEditMsgFlg))/*add by luning :only send vcardPart when pduBody have it for the moment*/ menu.add(0, MENU_ADD_ATTACHMENT, 0, R.string.add_attachment).setIcon(R.drawable.ic_menu_attachment); // } // ======fixed CR<NEWMS00110179> by luning at 11-08-12 end====== } if (isPreparedForSending() && !SENT.equals(boxType) && (!OUTBOX.equals(boxType) || outboxEditMsgFlg)) { menu.add(0, MENU_SEND, 0, R.string.send).setIcon(android.R.drawable.ic_menu_send); } /*======fixed CR<NEWMS00153060> by luning at 11-12-26 begin======*/ if ((!mWorkingMessage.requiresMms() || !mWorkingMessage.hasSlideshow() || mWorkingMessage.getSlideshow().isSimpleSlide()) && !SENT.equals(boxType) && (!OUTBOX.equals(boxType) || outboxEditMsgFlg) && mTextEditor.hasFocus()) /*======fixed CR<NEWMS00153060> by luning at 11-12-26 end======*/ { menu.add(0, MENU_INSERT_SMILEY, 0, R.string.menu_insert_smiley).setIcon(R.drawable.ic_menu_emoticons); } if (mMsgListAdapter.getCount() > 0 && !"true".equals(boxmsgFlg)) { // Removed search as part of b/1205708 //menu.add(0, MENU_SEARCH, 0, R.string.menu_search).setIcon( // R.drawable.ic_menu_search); Cursor cursor = mMsgListAdapter.getCursor(); if ((null != cursor) && (cursor.getCount() > 0)) { menu.add(0, MENU_DELETE_THREAD, 0, R.string.delete_thread) .setIcon(android.R.drawable.ic_menu_delete); } } else { if (!SENT.equals(boxType) && (!OUTBOX.equals(boxType) || outboxEditMsgFlg)) { menu.add(0, MENU_DISCARD, 0, R.string.discard).setIcon(android.R.drawable.ic_menu_delete); } } if (!"true".equals(boxmsgFlg)) { menu.add(0, MENU_CONVERSATION_LIST, 0, R.string.all_threads).setIcon(R.drawable.ic_menu_friendslist); } buildAddAddressToContactMenuItem(menu); return true; } private void buildAddAddressToContactMenuItem(Menu menu) { // Look for the first recipient we don't have a contact for and create a menu item to // add the number to contacts. for (Contact c : getRecipients()) { if (!c.existsInDatabase() && canAddToContacts(c) && !composeIsWapush()) { Intent intent = ConversationList.createAddContactIntent(c.getNumber()); menu.add(0, MENU_ADD_ADDRESS_TO_CONTACTS, 0, R.string.menu_add_to_contacts) .setIcon(android.R.drawable.ic_menu_add).setIntent(intent); break; } } } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case MENU_ADD_SUBJECT: showSubjectEditor(true); mWorkingMessage.setSubject("", true); mSubjectTextEditor.requestFocus(); break; case MENU_ADD_ATTACHMENT: // Launch the add-attachment list dialog IS_APPEND_MEDIA = true; showAddAttachmentDialog(false); break; case MENU_DISCARD: mWorkingMessage.discard(); finish(); break; case MENU_SEND: if (isPreparedForSending()) { confirmSendMessageIfNeeded(); } break; case MENU_SEARCH: onSearchRequested(); break; case MENU_DELETE_THREAD: confirmDeleteThread(mConversation.getThreadId()); break; case MENU_CONVERSATION_LIST: exitComposeMessageActivity(new Runnable() { public void run() { goToConversationList(); } }); break; case MENU_CALL_RECIPIENT: dialRecipient(); break; case MENU_VIDEOCALL_RECIPIENT: videodialRecipient(); break; case MENU_INSERT_SMILEY: showSmileyDialog(); break; case MENU_VIEW_CONTACT: { // View the contact for the first (and only) recipient. ContactList list = getRecipients(); if (list.size() == 1 && list.get(0).existsInDatabase()) { Uri contactUri = list.get(0).getUri(); Intent intent = new Intent(Intent.ACTION_VIEW, contactUri); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); startActivity(intent); } break; } case MENU_ADD_ADDRESS_TO_CONTACTS: mAddContactIntent = item.getIntent(); startActivityForResult(mAddContactIntent, REQUEST_CODE_ADD_CONTACT); break; } return true; } private void confirmDeleteThread(long threadId) { Conversation.startQueryHaveLockedMessages(mBackgroundQueryHandler, threadId, ConversationList.HAVE_LOCKED_MESSAGES_TOKEN); } // static class SystemProperties { // TODO, temp class to get unbundling working // static int getInt(String s, int value) { // return value; // just return the default value or now // } // } private int getVideoCaptureDurationLimit() { return CamcorderProfile.get(CamcorderProfile.QUALITY_LOW).duration; } private void addAttachment(int type, boolean replace) { // Calculate the size of the current slide if we're doing a replace so the // slide size can optionally be used in computing how much room is left for an attachment. //Lino modify for NEWMS00136133 begin 2011-11-03 ((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE)).toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS); //Lino modify for NEWMS00136133 end 2011-11-03 int currentSlideSize = 0; SlideshowModel slideShow = mWorkingMessage.getSlideshow(); if (replace && slideShow != null) { SlideModel slide = slideShow.get(0); currentSlideSize = slide.getSlideSize(); } switch (type) { case AttachmentTypeSelectorAdapter.ADD_IMAGE: MessageUtils.selectImage(this, REQUEST_CODE_ATTACH_IMAGE); break; case AttachmentTypeSelectorAdapter.TAKE_PICTURE: { Log.d(TAG, "position take picture "); Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); //intent.putExtra(MediaStore.EXTRA_OUTPUT, Mms.ScrapSpace.CONTENT_URI); intent.putExtra(MediaStore.EXTRA_OUTPUT, TempFileProvider.SCRAP_CONTENT_URI); startActivityForResult(intent, REQUEST_CODE_TAKE_PICTURE); break; } case AttachmentTypeSelectorAdapter.ADD_VIDEO: MessageUtils.selectVideo(this, REQUEST_CODE_ATTACH_VIDEO); break; case AttachmentTypeSelectorAdapter.RECORD_VIDEO: long sizeLimit = computeAttachmentSizeLimit(slideShow, currentSlideSize); if (sizeLimit > 0) { int durationLimit = getVideoCaptureDurationLimit(); Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0); intent.putExtra("android.intent.extra.sizeLimit", sizeLimit); intent.putExtra("android.intent.extra.durationLimit", durationLimit); startActivityForResult(intent, REQUEST_CODE_TAKE_VIDEO); } else { Toast.makeText(this, getString(R.string.message_too_big_for_video), Toast.LENGTH_SHORT).show(); } break; case AttachmentTypeSelectorAdapter.ADD_SOUND: MessageUtils.selectAudio(this, REQUEST_CODE_ATTACH_SOUND); break; case AttachmentTypeSelectorAdapter.RECORD_SOUND: MessageUtils.recordSound(this, REQUEST_CODE_RECORD_SOUND); break; case AttachmentTypeSelectorAdapter.ADD_VCARD: Intent mintent = new Intent("com.android.contacts.MULTIOPERATELIST"); mintent.putExtra("mode", MODE_MMS_VCARD_CONTACTS); mintent.putExtra("group", GROUP_ALL); startActivityForResult(mintent, REQUEST_CODE_ADD_ATTACHMENT); break; case AttachmentTypeSelectorAdapter.ADD_SLIDESHOW: editSlideshow(); break; default: break; } } public static long computeAttachmentSizeLimit(SlideshowModel slideShow, int currentSlideSize) { // Set video size limit. Subtract 1K for some text. long sizeLimit = MmsConfig.getMaxMessageSize() - SlideshowModel.SLIDESHOW_SLOP; if (slideShow != null) { sizeLimit -= slideShow.getTotalMsgSizeWithSlideHead(); // We're about to ask the camera to capture some video which will // eventually replace the content on the current slide. Since the current // slide already has some content (which was subtracted out just above) // and that content is going to get replaced, we can add the size of the // current slide into the available space used to capture a video. sizeLimit += currentSlideSize; } return sizeLimit; } private void showAddAttachmentDialog(final boolean replace) { if (mAttachmentTypeSelectorAdapter == null) { mAttachmentTypeSelectorAdapter = new AttachmentTypeSelectorAdapter(this, AttachmentTypeSelectorAdapter.MODE_WITH_SLIDESHOW); } if (mAttachmentDialogBuilder == null || replace) { mAttachmentDialogBuilder = new AlertDialog.Builder(this); mAttachmentDialogBuilder.setIcon(R.drawable.ic_dialog_attach); mAttachmentDialogBuilder.setTitle(R.string.add_attachment); mAttachmentDialogBuilder.setAdapter(mAttachmentTypeSelectorAdapter, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { addAttachment(mAttachmentTypeSelectorAdapter.buttonToCommand(which), replace); dialog.dismiss(); } }); } if (mAttachmentDialog == null || replace) { mAttachmentDialog = mAttachmentDialogBuilder.create(); } mAttachmentDialog.show(); } private void resolveContacts(Intent intent) { // ArrayList<ContentValues> contacts = // intent.getParcelableArrayListExtra("ContactsForMms"); // ===== fixed CR<NEWMS00135995> by luning at 11-11-04 begin ===== // String text = mRecipientsEditor.getText().toString().trim(); // int length = text.length(); // if(length != 0 && text.charAt(length - 1) != ','){ // mRecipientsEditor.append(", "); // } int contactSize = intent.getIntExtra("count", 0); String contactStr = intent.getStringExtra("ContactsForMms"); // ===== fixed CR<NEWMS00135995> by luning at 11-11-04 end ===== if (contactSize > RECIPIENTS_MAX_MUBER && contactStr != null) { final AlertDialog.Builder builder = new AlertDialog.Builder(ComposeMessageActivity.this); builder.setTitle(R.string.to_many_contacts); builder.setIcon(android.R.drawable.ic_dialog_alert); builder.setMessage(R.string.to_many_contacts_body); builder.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }); builder.show(); } else if (contactStr != null) { //int temp=0; StringBuffer allStr = new StringBuffer(); String[] singleStr = contactStr.split("\r\n"); String text = null; for (int i = 0; i < contactSize; i++) { text = mRecipientsEditor.getText().toString().trim(); int length = text.length(); if (length != 0 && text.charAt(length - 1) != ',') { mRecipientsEditor.append(", "); } // ===== fixed CR<NEWMS00135995> by luning at 11-11-04 end ===== /* * ContentValues map = contacts.get(i); String name = * map.getAsString(Contacts.DISPLAY_NAME); String number = * map.getAsString("number"); */ String map = singleStr[i]; final String CR = "\r"; final String CRLF = "\r\n"; String[] sp = map.split(CR); String name = sp[0]; String number = sp[1]; String nameAndnumber = ""; if (name.equals(number)) { nameAndnumber = " <" + number + ">, "; } else { nameAndnumber = name + " <" + number + ">, "; } if (text.contains(nameAndnumber.trim())) { continue; } // ===== fixed CR<NEWMS00135995> by luning at 11-11-04 end ===== SpannableString s = new SpannableString(nameAndnumber); s.setSpan(new Annotation("name", name), 0, name.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); s.setSpan(new Annotation("number", number), 0, number.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); if ((mRecipientsEditor.length() + s.length()) >= RECIPIENTS_MAX_LENGTH) { //temp ++; continue; } mRecipientsEditor.append(s); // ===== fixed CR<NEWMS00135995> by luning at 11-11-04 end ===== } } mRecipientsEditor.requestFocus(); } // modify by dory.zheng for NEWMS00137013 begin // if(temp > 0){ // Toast.makeText(ComposeMessageActivity.this, // R.string.contacts_max_exceed, Toast.LENGTH_SHORT) // .show(); // } // modify by dory.zheng for NEWMS00137013 end @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (DEBUG) { log("requestCode=" + requestCode + ", resultCode=" + resultCode + ", data=" + data); } mWaitingForSubActivity = false; // We're back! if (mWorkingMessage.isFakeMmsForDraft()) { // We no longer have to fake the fact we're an Mms. At this point we are or we aren't, // based on attachments and other Mms attrs. mWorkingMessage.removeFakeMmsForDraft(); } // If there's no data (because the user didn't select a picture and // just hit BACK, for example), there's nothing to do. //if (requestCode != REQUEST_CODE_TAKE_PICTURE) { //if (data == null) { // return; //} //} else if (resultCode != RESULT_OK){ if (resultCode != RESULT_OK) { if (DEBUG) log("bail due to resultCode=" + resultCode); return; } switch (requestCode) { case REQUEST_CODE_CREATE_SLIDESHOW: if (data != null) { CharSequence subject = mWorkingMessage.getSubject(); boolean notify = !mWorkingMessage.hasAttachment(); WorkingMessage newMessage = WorkingMessage.load(this, data.getData(), notify); if (newMessage != null) { mWorkingMessage = newMessage; mWorkingMessage.setConversation(mConversation); mAttachmentEditor.update(mWorkingMessage); mWorkingMessage.setSubject(subject, false); drawTopPanel(); updateSendButtonState(); //if (mWorkingMessage.hasSlideshow()) { // this.toastConvertInfo(true); //} else { // this.toastConvertInfo(false); //} } } break; case REQUEST_CODE_TAKE_PICTURE: { // create a file based uri and pass to addImage(). We want to read the JPEG // data directly from file (using UriImage) instead of decoding it into a Bitmap, // which takes up too much memory and could easily lead to OOM. Log.d(TAG, "REQUEST_CODE_TAKE_PICTURE result"); Log.d(TAG, "new RotatePictureTask().execute((Void)null); Enter"); new RotatePictureTask().execute((Void) null); Log.d(TAG, "new RotatePictureTask().execute((Void)null); Leave"); break; } case REQUEST_CODE_ATTACH_IMAGE: { addImage(data.getData(), false); break; } case REQUEST_CODE_TAKE_VIDEO: case REQUEST_CODE_ATTACH_VIDEO: addVideo(data.getData(), false); break; case REQUEST_CODE_ATTACH_SOUND: { Uri uri = (Uri) data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI); //----maybe the uri not sound,then the uri will be null.-start---- if (uri == null) { Toast.makeText(ComposeMessageActivity.this, R.string.re_select_media, Toast.LENGTH_SHORT).show(); break; } //----end.--------------------------------------------------------- if (Settings.System.DEFAULT_RINGTONE_URI.equals(uri)) { break; } addAudio(uri, false); break; } case REQUEST_CODE_RECORD_SOUND: addAudio(data.getData(), false); break; case REQUEST_CODE_ECM_EXIT_DIALOG: boolean outOfEmergencyMode = data.getBooleanExtra(EXIT_ECM_RESULT, false); if (outOfEmergencyMode) { sendMessage(false); } break; case REQUEST_CODE_ADD_CONTACT: // The user just added a new contact. We saved the contact info in // mAddContactIntent. Get the contact and force our cached contact to // get reloaded with the new info (such as contact name). After the // contact is reloaded, the function onUpdate() in this file will get called // and it will update the title bar, etc. Log.i(TAG, "Add Contacts"); if (mAddContactIntent != null) { String address = mAddContactIntent.getStringExtra(ContactsContract.Intents.Insert.EMAIL); if (address == null) { address = mAddContactIntent.getStringExtra(ContactsContract.Intents.Insert.PHONE); } if (address != null) { Contact contact = Contact.get(address, false); if (contact != null) { contact.reload(); } } } break; //yeezone:jinwei add selected contacts case REQUESET_CODE_SELECT_CONTACTS: resolveContacts(data); break; case REQUEST_CODE_ADD_ATTACHMENT: String type = data.getType(); Uri stream = (Uri) data.getParcelableExtra(Intent.EXTRA_STREAM); addAttachment(type, stream, false); default: // TODO break; } //===== fixed CR<NEWSM00125959> by luning at 11-09-26 begin ===== //default is append media //IS_APPEND_MEDIA = true; //===== fixed CR<NEWSM00125959> by luning at 11-09-26 end ===== } private int getPositionOfadd() { if (mWorkingMessage.getSlideshow() == null) { Log.d(TAG, "mWorkingMessage.getSlideshow() == null"); return 0; } Log.d(TAG, "IS_APPEND_MEDIA == " + IS_APPEND_MEDIA); if (!IS_APPEND_MEDIA) { return 0; } SlideshowModel slides = mWorkingMessage.getSlideshow(); for (int i = 0; i < slides.size(); i++) { if (!slides.get(i).hasImage() && !slides.get(i).hasVideo()) { return i; } } return slides.size(); } private ResizeImageResultCallback mResizeImageCallback = new ResizeImageResultCallback() { // TODO: make this produce a Uri, that's what we want anyway public void onResizeResult(PduPart part, boolean append) { if (part == null) { handleAddAttachmentError(WorkingMessage.UNKNOWN_ERROR, R.string.type_picture); return; } Context context = ComposeMessageActivity.this; PduPersister persister = PduPersister.getPduPersister(context); int result; if (!mWorkingMessage.isDiscarded()) { Uri messageUri = mWorkingMessage.saveAsMms(true); try { Uri dataUri = persister.persistPart(part, ContentUris.parseId(messageUri)); //===== fixed CR<NEWSM00125959> by luning at 11-09-26 begin ===== // result = mWorkingMessage.setAttachment(WorkingMessage.IMAGE, dataUri, append); result = mWorkingMessage.addAttachment(WorkingMessage.IMAGE, dataUri); //===== fixed CR<NEWSM00125959> by luning at 11-09-26 end ===== if (DEBUG || Log.isLoggable(LogTag.APP, Log.VERBOSE)) { log("ResizeImageResultCallback: dataUri=" + dataUri); } } catch (MmsException e) { result = WorkingMessage.UNKNOWN_ERROR; } handleAddAttachmentError(result, R.string.type_picture); } } }; private void handleAddAttachmentError(final int error, final int mediaTypeStringId) { if (error == WorkingMessage.OK) { return; } runOnUiThread(new Runnable() { public void run() { Resources res = getResources(); String mediaType = res.getString(mediaTypeStringId); String title, message; switch (error) { case WorkingMessage.UNSUPPORTED_TYPE: title = res.getString(R.string.unsupported_media_format, mediaType); message = res.getString(R.string.select_different_media, mediaType); break; case WorkingMessage.MESSAGE_SIZE_EXCEEDED: title = res.getString(R.string.exceed_message_size_limitation, mediaType); message = res.getString(R.string.failed_to_add_media, mediaType); break; case WorkingMessage.IMAGE_TOO_LARGE: title = res.getString(R.string.failed_to_resize_image); message = res.getString(R.string.resize_image_error_information); break; case WorkingMessage.SLIDE_MAX: message = res.getString(R.string.cannot_add_slide_anymore, mediaType); Toast.makeText(ComposeMessageActivity.this, message, Toast.LENGTH_SHORT).show(); return; case WorkingMessage.UNKNOWN_ERROR: default: message = res.getString(R.string.failed_to_add_media, mediaType); Toast.makeText(ComposeMessageActivity.this, message, Toast.LENGTH_SHORT).show(); return; // throw new IllegalArgumentException("unknown error " + error); } MessageUtils.showErrorDialog(ComposeMessageActivity.this, title, message); } }); } private void addImage(Uri uri, boolean append) { if (DEBUG || Log.isLoggable(LogTag.APP, Log.VERBOSE)) { log("append=" + append + ", uri=" + uri + ", IS_APPEND_MEDIA= " + IS_APPEND_MEDIA + ", hasAttachment= " + mWorkingMessage.hasAttachment()); } // ======fixed CR<NEWMS00110179> by luning at 11-08-12 begin====== int result = 0; if (IS_APPEND_MEDIA && mWorkingMessage.hasAttachment()) { result = mWorkingMessage.addAttachment(WorkingMessage.IMAGE, uri); } else { result = mWorkingMessage.setAttachment(WorkingMessage.IMAGE, uri, false); } // ======fixed CR<NEWMS00110179> by luning at 11-08-12 end====== if (result == WorkingMessage.IMAGE_TOO_LARGE || result == WorkingMessage.MESSAGE_SIZE_EXCEEDED) { if (DEBUG || Log.isLoggable(LogTag.APP, Log.VERBOSE)) { log("resize image " + uri); } MessageUtils.resizeImageAsync(this, uri, mAttachmentEditorHandler, mResizeImageCallback, append); return; } handleAddAttachmentError(result, R.string.type_picture); } private void addVideo(Uri uri, boolean append) { if (uri != null) { // ======fixed CR<NEWMS00110179> by luning at 11-08-12 begin====== int result = 0; if (IS_APPEND_MEDIA && mWorkingMessage.hasAttachment()) { result = mWorkingMessage.addAttachment(WorkingMessage.VIDEO, uri); } else { result = mWorkingMessage.setAttachment(WorkingMessage.VIDEO, uri, false); } // ======fixed CR<NEWMS00110179> by luning at 11-08-12 end====== handleAddAttachmentError(result, R.string.type_video); } } private void addVcard(Uri uri, boolean append) { if (uri != null) { int result = 0; if (IS_APPEND_MEDIA && mWorkingMessage.hasAttachment()) { result = mWorkingMessage.addAttachment(WorkingMessage.VCARD, uri); } else { result = mWorkingMessage.setAttachment(WorkingMessage.VCARD, uri, append); } handleAddAttachmentError(result, R.string.type_vcard); } } private void addVcard(Uri uri, boolean append, boolean isAppendMedia) { if (uri != null) { int result = 0; if (isAppendMedia && mWorkingMessage.hasAttachment()) { result = mWorkingMessage.addAttachment(WorkingMessage.VCARD, uri); } else { result = mWorkingMessage.setAttachment(WorkingMessage.VCARD, uri, append); } handleAddAttachmentError(result, R.string.type_vcard); } } private void addOtherFile(Uri uri, boolean append) { if (uri != null) { int result = 0; if (mWorkingMessage.hasAttachment()) { result = mWorkingMessage.addAttachment(WorkingMessage.OTHER_FILE, uri); } else { result = mWorkingMessage.setAttachment(WorkingMessage.OTHER_FILE, uri, append); } handleAddAttachmentError(result, R.string.type_file); } } private void addAudio(Uri uri, boolean append) { // ======fixed CR<NEWMS00110179> by luning at 11-08-12 begin====== int result = 0; if (IS_APPEND_MEDIA && mWorkingMessage.hasAttachment()) { result = mWorkingMessage.addAttachment(WorkingMessage.AUDIO, uri); } else { result = mWorkingMessage.setAttachment(WorkingMessage.AUDIO, uri, append); } // ======fixed CR<NEWMS00110179> by luning at 11-08-12 end====== handleAddAttachmentError(result, R.string.type_audio); } private boolean handleForwardedMessage() { Intent intent = getIntent(); // If this is a forwarded message, it will have an Intent extra // indicating so. If not, bail out. if (intent == null || mWorkingMessage == null || mMsgListAdapter == null || intent.getBooleanExtra("forwarded_message", false) == false) { return false; } Uri uri = intent.getParcelableExtra("msg_uri"); String nameAndnumber = ""; SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); if (sp.getBoolean(MessagingPreferenceActivity.FORWARDING_NUMBER, true)) { String senderNumber = intent.getStringExtra("sender_number"); Contact contact = Contact.get(senderNumber, false); String text = mRecipientsEditor.getText().toString().trim(); int length = text.length(); if (length != 0 && text.charAt(length - 1) != ',') { mRecipientsEditor.append(", "); } String name = contact.getName(); String number = contact.getNumber(); if (name.equals(number)) { nameAndnumber = " <" + number + ">, "; } else { nameAndnumber = name + " <" + number + ">, "; } } if (Log.isLoggable(LogTag.APP, Log.DEBUG)) { log("" + uri); } if (uri != null) { mWorkingMessage = WorkingMessage.load(this, uri, true); if (mWorkingMessage == null) { Toast.makeText(this, R.string.handle_forward_error, Toast.LENGTH_LONG); return false; } mWorkingMessage.setSubject(intent.getStringExtra("subject"), false); } else { mWorkingMessage.setText(nameAndnumber + intent.getStringExtra("sms_body")); } // let's clear the message thread for forwarded messages mMsgListAdapter.changeCursor(null); return true; } private boolean handleSendIntent(Intent intent) { Bundle extras = intent.getExtras(); if (extras == null) { return false; } final String mimeType = intent.getType(); String action = intent.getAction(); if (Intent.ACTION_SEND.equals(action)) { if (extras.containsKey(Intent.EXTRA_STREAM)) { Uri uri = (Uri) extras.getParcelable(Intent.EXTRA_STREAM); addAttachment(mimeType, uri, false); return true; } else if (extras.containsKey(Intent.EXTRA_TEXT)) { mWorkingMessage.setText(extras.getString(Intent.EXTRA_TEXT)); return true; } } else if ("android.intent.action.SEND_SIM".equals(action)) { String cName = extras.getString("name"); String cNumber = extras.getString("number"); final ByteArrayOutputStream localStream = new ByteArrayOutputStream(); final VCardComposer composer = new VCardComposer(ComposeMessageActivity.this, VCardConfig.VCARD_TYPE_DEFAULT, false); composer.addHandler(composer.new HandlerForOutputStream(localStream)); // if (!composer.init(cName)) { // Log.e(TAG, "Failed to init VCardComposer"); // return true; // } // if (!composer.createOneEntry(cName, cNumber)) { // Log.e(TAG, "Failed to output a contact."); // } composer.terminate(); //fix for bug 4045 by phone_02, create the sim card Contacts and send VCardBuilder builder = new VCardBuilder(VCardConfig.getVCardTypeFromString("default")); ContentValues values = new ContentValues(); values.put(StructuredName.DISPLAY_NAME, cName); ArrayList<ContentValues> list = new ArrayList<ContentValues>(); list.add(values); builder.appendNameProperties(list); values = new ContentValues(); values.put(Phone.NUMBER, cNumber); list = new ArrayList<ContentValues>(); list.add(values); builder.appendPhones(list); //final byte[] byteData = localStream.toByteArray(); byte[] byteData = null; try { byteData = builder.toString().getBytes("UTF-8"); } catch (UnsupportedEncodingException e1) { e1.printStackTrace(); Log.e("TAG", "UnsupportedEncodingException~~~", e1); } File f = new File("/data/data/com.android.mms/" + cName + ".vcf"); FileOutputStream fos = null; try { if (!f.exists()) { f.createNewFile(); } fos = new FileOutputStream(f); fos.write(byteData); Uri uri = Uri.fromFile(f); addAttachment(mimeType, uri, false); return true; } catch (Exception e) { Log.e(TAG, "send contact:" + e.toString()); Toast.makeText(ComposeMessageActivity.this, "send sim contact error", Toast.LENGTH_LONG); } finally { try { localStream.close(); fos.close(); } catch (Exception e) { Log.e(TAG, "close stream failed" + e.toString()); } } } else if (Intent.ACTION_SEND_MULTIPLE.equals(action) && extras.containsKey(Intent.EXTRA_STREAM)) { SlideshowModel slideShow = mWorkingMessage.getSlideshow(); final ArrayList<Parcelable> uris = extras.getParcelableArrayList(Intent.EXTRA_STREAM); int currentSlideCount = slideShow != null ? slideShow.size() : 0; int importCount = uris.size(); if (importCount + currentSlideCount > SlideshowEditor.MAX_SLIDE_NUM) { importCount = Math.min(SlideshowEditor.MAX_SLIDE_NUM - currentSlideCount, importCount); Toast.makeText(ComposeMessageActivity.this, getString(R.string.too_many_attachments, SlideshowEditor.MAX_SLIDE_NUM, importCount), Toast.LENGTH_LONG).show(); } // Attach all the pictures/videos off of the UI thread. // Show a progress alert if adding all the slides hasn't finished // within one second. // Stash the runnable for showing it away so we can cancel // it later if adding completes ahead of the deadline. final AlertDialog dialog = new AlertDialog.Builder(ComposeMessageActivity.this) .setIcon(android.R.drawable.ic_dialog_alert).setTitle(R.string.adding_attachments_title) .setMessage(R.string.adding_attachments).create(); final Runnable showProgress = new Runnable() { public void run() { dialog.show(); } }; // Schedule it for one second from now. mAttachmentEditorHandler.postDelayed(showProgress, 1000); final int numberToImport = importCount; new Thread(new Runnable() { public void run() { for (int i = 0; i < numberToImport; i++) { Parcelable uri = uris.get(i); addAttachment(mimeType, (Uri) uri, true); } // Cancel pending show of the progress alert if necessary. mAttachmentEditorHandler.removeCallbacks(showProgress); dialog.dismiss(); } }, "addAttachment").start(); return true; } return false; } // mVideoUri will look like this: content://media/external/video/media private static final String mVideoUri = Video.Media.getContentUri("external").toString(); // mImageUri will look like this: content://media/external/images/media private static final String mImageUri = Images.Media.getContentUri("external").toString(); private void addAttachment(String type, Uri uri, boolean append) { if (uri != null) { // When we're handling Intent.ACTION_SEND_MULTIPLE, the passed in items can be // videos, and/or images, and/or some other unknown types we don't handle. When // a single attachment is "shared" the type will specify an image or video. When // there are multiple types, the type passed in is "*/*". In that case, we've got // to look at the uri to figure out if it is an image or video. if (uri.getScheme().equals("file")) { type = getSharedFileType(uri); } boolean wildcard = "*/*".equals(type); if (type.startsWith("image/") || (wildcard && uri.toString().startsWith(mImageUri))) { addImage(uri, append); } else if (type.startsWith("video/") || (wildcard && uri.toString().startsWith(mVideoUri))) { addVideo(uri, append); } else if (type.equals("text/x-vcard")) { is_vcard_adding = true; mVcardProgressDialog = new ProgressDialog(this); mVcardProgressDialog.setMessage(getString(R.string.on_progress)); mVcardProgressDialog.setIndeterminate(true); mVcardProgressDialog.setCancelable(false); mVcardProgressDialog.show(); mEventHandler = new VcardProgressHandler(getMainLooper()); Thread t = new myThread(uri, append, IS_APPEND_MEDIA); t.start(); //addVcard(uri, append); } else if (type.startsWith("audio/")) {// 20120229 bug 11791 addAudio(uri, append); } else { addOtherFile(uri, append); } // else { // // final Runnable showToast = new Runnable() { // public void run() { // Toast.makeText(ComposeMessageActivity.this, // R.string.share_not_support_contentType, Toast.LENGTH_LONG).show(); // } // }; // mAttachmentEditorHandler.postDelayed(showToast, 500); // // } } } private String getSharedFileType(Uri uri) { Log.d(TAG, "getSharedFileType -> The passed uri is " + uri); String path = uri.getPath(); String contentType; MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton(); String extension = MimeTypeMap.getFileExtensionFromUrl(path); if (TextUtils.isEmpty(extension)) { // getMimeTypeFromExtension() doesn't handle spaces in filenames nor can it handle // urlEncoded strings. Let's try one last time at finding the extension. int dotPos = path.lastIndexOf('.'); if (0 <= dotPos) { extension = path.substring(dotPos + 1); } } contentType = mimeTypeMap.getMimeTypeFromExtension(extension); Log.d(TAG, "Shared file Content Type is: " + contentType); return contentType; } private String getResourcesString(int id, String mediaName) { Resources r = getResources(); return r.getString(id, mediaName); } private void drawBottomPanel() { // Reset the counter for text editor. resetCounter(); // ===== fixed CR<NEWMS00129480> by luning at 11-10-13 begin ===== // if (mWorkingMessage.hasSlideshow()) if ((mWorkingMessage.hasSlideshow() && !mWorkingMessage.getSlideshow().isSimpleSlide()) || ("true".equals(boxmsgFlg) && (OUTBOX.equals(boxType) || SENT.equals(boxType)))) // ===== fixed CR<NEWMS00129480> by luning at 11-10-13 end ===== { if (!outboxEditMsgFlg) { mBottomPanel.setVisibility(View.GONE); mAttachmentEditor.requestFocus(); return; } } mBottomPanel.setVisibility(View.VISIBLE); CharSequence text = mWorkingMessage.getText(); // TextView.setTextKeepState() doesn't like null input. if (text != null) { mTextEditor.setTextKeepState(text); } else { mTextEditor.setText(""); } } private void drawTopPanel() { showSubjectEditor(mWorkingMessage.hasSubject()); } //========================================================== // Interface methods //========================================================== public void onClick(View v) { if ((v == mSendButton) && isPreparedForSending()) { Log.d(TAG, "[sms]onClick send button mSmsReady[0]=" + mSmsReady[0] + " mSmsReady[1]=" + mSmsReady[1]); confirmSendMessageIfNeeded(); // list.clear();/*delete for CR<NEWMS00135995> by luning at 11-11-04 */ } else if (v == mContactsSelectButton) { //modify by dory.zheng for NEWMS00120648 at 15-09 begin displayContactsDialog(); // Intent intent = new Intent("com.android.contacts.MULTIOPERATELIST"); // startActivityForResult(intent, REQUESET_CODE_SELECT_CONTACTS); //modify by dory.zheng for NEWMS00120648 at 15-09 end } } //add by dory.zheng for NEWMS00120648 at 15-09 begin private boolean simCardReady() { Log.v(TAG, "getSimState = " + ((TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE)).getSimState()); if (TelephonyManager.SIM_STATE_READY == ((TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE)) .getSimState()) { Log.v(TAG, "sim ready"); return true; } else { Toast.makeText(this, getString(R.string.sim_no_ready), Toast.LENGTH_SHORT).show(); return false; } } private boolean simCardReady(int phoneId) { TelephonyManager telManager = (TelephonyManager) getSystemService( PhoneFactory.getServiceName(Context.TELEPHONY_SERVICE, phoneId)); boolean hasSim = (null != telManager) ? telManager.hasIccCard() : false; if (hasSim && telManager.getSimState() == TelephonyManager.SIM_STATE_READY) { Log.v(TAG, "sim ready"); return true; } else { Toast.makeText(this, getString(R.string.sim_no_ready), Toast.LENGTH_SHORT).show(); return false; } } private void displayContactsDialog() { // Wrap our context to inflate list items using correct theme final Context dialogContext = new ContextThemeWrapper(this, android.R.style.Theme_Light); final Resources res = dialogContext.getResources(); final LayoutInflater dialogInflater = (LayoutInflater) dialogContext .getSystemService(Context.LAYOUT_INFLATER_SERVICE); // Adapter that shows a list of string resources final ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1) { @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = dialogInflater.inflate(android.R.layout.simple_list_item_1, parent, false); } final String resString = this.getItem(position); ((TextView) convertView).setText(resString); return convertView; } }; adapter.add(getString(R.string.group_all)); adapter.add(getString(R.string.group_phone)); if (MessageUtils.isMSMS) { // TelephonyManager telManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); TelephonyManager telManager = (TelephonyManager) getSystemService( PhoneFactory.getServiceName(Context.TELEPHONY_SERVICE, 0)); TelephonyManager telManager2 = (TelephonyManager) getSystemService( PhoneFactory.getServiceName(Context.TELEPHONY_SERVICE, 1)); boolean hasSim1 = (null != telManager) ? telManager.hasIccCard() : false; boolean hasSim2 = (null != telManager2) ? telManager2.hasIccCard() : false; if (hasSim1 && telManager.getSimState() == TelephonyManager.SIM_STATE_READY) { adapter.add(getString(R.string.group_sim1)); } if (hasSim2 && telManager2.getSimState() == TelephonyManager.SIM_STATE_READY) { adapter.add(getString(R.string.group_sim2)); } } else { if (TelephonyManager.SIM_STATE_READY == ((TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE)) .getSimState()) { adapter.add(getString(R.string.group_sim)); } } final Map<Integer, String> dividedNameMap = new HashMap<Integer, String>(); Cursor cursor = this.getContentResolver().query(DIVIDED_GROUP_URI, null, null, null, null); String tmp; int id; while (cursor.moveToNext()) { tmp = cursor.getString(cursor.getColumnIndexOrThrow("divided_name")); id = cursor.getInt(cursor.getColumnIndexOrThrow(BaseColumns._ID)); //for bugzilla 13822 if (/*!TextUtils.isEmpty(tmp && */id < 4 && id > -1) { tmp = getDeafaultGroupName(id); } dividedNameMap.put(id, tmp); adapter.add(tmp); } if (cursor != null) { cursor.close(); } final DialogInterface.OnClickListener clickListener = new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); // // for group final String resString = adapter.getItem(which); int mContactsGroupNameId = -1; Intent intent = new Intent("com.android.contacts.MULTIOPERATELIST"); if (dividedNameMap.size() > 0) { for (Entry<Integer, String> tmp : dividedNameMap.entrySet()) { if (tmp.getValue() == resString) { mContactsGroupNameId = tmp.getKey(); } } } if (resString == getString(R.string.group_all)) { intent.putExtra("type", GROUP_ALL); } else if (resString == getString(R.string.group_phone)) { intent.putExtra("type", GROUP_PHONE); } else if (resString == getString(R.string.group_sim)) { intent.putExtra("type", GROUP_SIM); if (!simCardReady()) { return; } } else if (resString == getString(R.string.group_sim1)) { intent.putExtra("type", GROUP_SIM1); if (!simCardReady(0)) { return; } } else if (resString == getString(R.string.group_sim2)) { intent.putExtra("type", GROUP_SIM2); if (!simCardReady(1)) { return; } } else { Log.d(TAG, "Unexpected resource."); } if (mContactsGroupNameId != -1) { intent.putExtra("groupNameId", mContactsGroupNameId); } intent.putExtra("group", MODE_PICK); intent.putExtra("limit", RECIPIENTS_MAX_MUBER); if (mRecipientsEditor.getRecipientCount() > 0) { mWorkingMessage.discard(); } startActivityForResult(intent, REQUESET_CODE_SELECT_CONTACTS); } }; new AlertDialog.Builder(this).setTitle(R.string.select_contacts_group) .setNegativeButton(android.R.string.cancel, null).setSingleChoiceItems(adapter, -1, clickListener) .show(); } //add by dory.zheng for NEWMS00120648 at 15-09 begin public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { if (event != null) { // if shift key is down, then we want to insert the '\n' char in the TextView; // otherwise, the default action is to send the message. if (!event.isShiftPressed() && event .getAction() == KeyEvent.ACTION_DOWN/*fixed CR<NEWMS00142440> by luning at 2011.11.19*/) { if (isPreparedForSending()) { confirmSendMessageIfNeeded(); } return true; } return false; } if (isPreparedForSending()) { confirmSendMessageIfNeeded(); } return true; } /** * @param s input string to judge * @return if string contained chinese character will return true, else */ private boolean isContainChinese(CharSequence s) { for (int i = 0; i < s.length(); i++) { if (s.toString().codePointAt(i) > 128) { return true; } } return false; } private TextWatcher mTextEditorWatcher = new TextWatcher() { public void beforeTextChanged(CharSequence s, int start, int count, int after) { } public void onTextChanged(CharSequence s, int start, int before, int count) { // This is a workaround for bug 1609057. Since onUserInteraction() is // not called when the user touches the soft keyboard, we pretend it was // called when textfields changes. This should be removed when the bug // is fixed. onUserInteraction(); /*fixed CR<NEWMS00148018> by luning at 2011.12.13 begin*/ if (s.length() > MmsConfig.getmMaxTextLength()) { Toast.makeText(ComposeMessageActivity.this, getString(R.string.exceed_text_length_limitation), Toast.LENGTH_SHORT).show(); s = s.subSequence(0, MmsConfig.getmMaxTextLength()); mTextEditor.setText(s); Editable editable = mTextEditor.getEditableText(); Selection.setSelection(editable, editable.length()); } checkMessageSize(s, MmsConfig.getmMaxTextLength(), getTextOldLen()); if (mTxtCompareRst != TextCompareResult.NOEXCEED_ANY_SIZE) { if (mTxtCompareRst == TextCompareResult.EXCEED_MAX_MMS_SIZE) { showErDialog(); s = s.subSequence(0, mTxtLength); mTextEditor.setText(s); Editable editable = mTextEditor.getEditableText(); Selection.setSelection(editable, editable.length()); } else if (mTxtCompareRst == TextCompareResult.EXCEED_ORGINAL_MAX_MMS_SIZE) { if (s.length() > 0) { s = ""; mTextEditor.setText(s); showErDialog(); } } } /*fixed CR<NEWMS00148018> by luning at 2011.12.13 end*/ updateText(s); mWorkingMessage.setText(s); updateSendButtonState(); updateCounter(s, start, before, count); mAttachmentEditor.update(mWorkingMessage); //ensureCorrectButtonHeight(); //yeezone:jinwei set edited message count if (FeatureSwitch.COMPOSE_MESSAGE_TIP_SUPPORT) { if (s.length() == 0) { //mTitleRight.setText(LIMITED_MESSAGE_MAX_COUNT + "/" + 1); return; } //delete for wrong message count 20110722 } } public void afterTextChanged(Editable s) { } }; /** * Ensures that if the text edit box extends past two lines then the * button will be shifted up to allow enough space for the character * counter string to be placed beneath it. */ private void ensureCorrectButtonHeight() { int currentTextLines = mTextEditor.getLineCount(); if (currentTextLines <= 2) { mTextCounter.setVisibility(View.GONE); } else if (currentTextLines > 2 && mTextCounter.getVisibility() == View.GONE) { // Making the counter invisible ensures that it is used to correctly // calculate the position of the send button even if we choose not to // display the text. mTextCounter.setVisibility(View.INVISIBLE); } } private TextWatcher mSubjectEditorWatcher = new TextWatcher() { int length = 0; public void beforeTextChanged(CharSequence s, int start, int count, int after) { /* fixed CR<NEWMS00150391> by luning at 2011.12.14 begin*/ if (null != s) { length = s.length(); } /* fixed CR<NEWMS00150391> by luning at 2011.12.14 end*/ } public void onTextChanged(CharSequence s, int start, int before, int count) { /* fixed CR<NEWMS00150391> by luning at 2011.12.14 begin*/ /* fixed CR<NEWMS00150391> by luning at 2011.12.14 end*/ if (s.length() > MmsConfig.getmMaxSubjectSize()) { Toast.makeText(ComposeMessageActivity.this, getString(R.string.exceed_text_length_limitation), Toast.LENGTH_SHORT).show(); s = s.subSequence(0, MmsConfig.getmMaxSubjectSize()); mSubjectTextEditor.setText(s); Editable editable = mSubjectTextEditor.getEditableText(); Selection.setSelection(editable, editable.length()); } checkMessageSize(s, MmsConfig.getmMaxSubjectSize(), mWorkingMessage.getSubjectLength()); if (mTxtCompareRst != TextCompareResult.NOEXCEED_ANY_SIZE) { if (mTxtCompareRst == TextCompareResult.EXCEED_MAX_MMS_SIZE) { showErDialog(); s = s.subSequence(0, mTxtLength); mSubjectTextEditor.setText(s); Editable editable = mSubjectTextEditor.getEditableText(); Selection.setSelection(editable, editable.length()); } else if (mTxtCompareRst == TextCompareResult.EXCEED_ORGINAL_MAX_MMS_SIZE) { if (s.length() > 0) { s = ""; mSubjectTextEditor.setText(s); showErDialog(); } } } mWorkingMessage.setSubject(s, true); mAttachmentEditor.update(mWorkingMessage); } public void afterTextChanged(Editable s) { } }; //========================================================== // Private methods //========================================================== /** * Initialize all UI elements from resources. */ private void initResourceRefs() { if (FeatureSwitch.COMPOSE_MESSAGE_TIP_SUPPORT) { mTitleLeft = (TextView) findViewById(R.id.left_text); mTitleRight = (TextView) findViewById(R.id.right_text); } mMsgListView = (MessageListView) findViewById(R.id.history); mMsgListView.setDivider(null); // no divider so we look like IM conversation. mBottomPanel = findViewById(R.id.bottom_panel); mTextEditor = (EditText) findViewById(R.id.embedded_text_editor); //mTextEditor.setOnEditorActionListener(this); mTextEditor.addTextChangedListener(mTextEditorWatcher); mTextCounter = (TextView) findViewById(R.id.text_counter); mSendButton = (Button) findViewById(R.id.send_button); mSendButton.setOnClickListener(this); mContactsSelectButton = (Button) findViewById(R.id.contacts_import); mContactsSelectButton.setOnClickListener(this); mTopPanel = findViewById(R.id.recipients_subject_linear); mTopPanel.setFocusable(false); mAttachmentEditor = (AttachmentEditor) findViewById(R.id.attachment_editor); mAttachmentEditor.setHandler(mAttachmentEditorHandler); } private void confirmDeleteDialog(OnClickListener listener, boolean locked) { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(locked ? R.string.confirm_dialog_locked_title : R.string.confirm_dialog_title); builder.setIcon(android.R.drawable.ic_dialog_alert); builder.setCancelable(true); builder.setMessage(locked ? R.string.confirm_delete_locked_message : R.string.confirm_delete_message); builder.setPositiveButton(R.string.delete, listener); builder.setNegativeButton(R.string.no, null); builder.show(); } void undeliveredMessageDialog(long date) { String body; LinearLayout dialog = (LinearLayout) LayoutInflater.from(this).inflate(R.layout.retry_sending_dialog, null); if (date >= 0) { body = getString(R.string.undelivered_msg_dialog_body, MessageUtils.formatTimeStampString(this, date)); } else { // FIXME: we can not get sms retry time. body = getString(R.string.undelivered_sms_dialog_body); } ((TextView) dialog.findViewById(R.id.body_text_view)).setText(body); Toast undeliveredDialog = new Toast(this); undeliveredDialog.setView(dialog); undeliveredDialog.setDuration(Toast.LENGTH_LONG); undeliveredDialog.show(); } private void startMsgListQuery() { // for bug 9064 // if (mConversation.getRecipients().size() > 0) {/* fixed CR<NEWMS00143653> by luning at 2011.11.23*/ // mConversation.ensureThreadId();// ensure threadID first // } Uri conversationUri = null; String boxTypeInt = ""; if (INBOX.equals(boxType)) { boxTypeInt = "1"; } else if (OUTBOX.equals(boxType)) { boxTypeInt = "4"; } else if (SENT.equals(boxType)) { boxTypeInt = "2"; } else if (DRAFTS.equals(boxType)) { boxTypeInt = "3"; } if ("true".equals(boxmsgFlg) && !isLongPressSendFlg && !notificationFlg) { conversationUri = Uri.parse( "content://mms-sms/messageview/" + boxmsgThreadId + "/" + boxmsgMsgId + "/" + boxTypeInt); } else { conversationUri = mConversation.getUri(); } if (conversationUri == null) { return; } if (DEBUG || Log.isLoggable(LogTag.APP, Log.VERBOSE)) { log("for " + conversationUri); } // Cancel any pending queries mBackgroundQueryHandler.cancelOperation(MESSAGE_LIST_QUERY_TOKEN); try { // Kick off the new query mBackgroundQueryHandler.startQuery(MESSAGE_LIST_QUERY_TOKEN, null, conversationUri, PROJECTION, null, null, null); } catch (SQLiteException e) { SqliteWrapper.checkSQLiteException(this, e); } } private void initMessageList() { if (mMsgListAdapter != null) { return; } String highlightString = getIntent().getStringExtra("highlight"); Pattern highlight = highlightString == null ? null : Pattern.compile("\\b" + Pattern.quote(highlightString), Pattern.CASE_INSENSITIVE); // Initialize the list adapter with a null cursor. mMsgListAdapter = new MessageListAdapter(this, null, mMsgListView, true, highlight); mMsgListAdapter.setOnDataSetChangedListener(mDataSetChangedListener); mMsgListAdapter.setMsgListItemHandler(mMessageListItemHandler); mMsgListView.setAdapter(mMsgListAdapter); mMsgListView.setItemsCanFocus(false); mMsgListView.setVisibility(View.VISIBLE); mMsgListView.setOnCreateContextMenuListener(mMsgListMenuCreateListener); mMsgListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View view, int position, long id) { if (view != null) { ((MessageListItem) view).onMessageListItemClick(); } } }); //new ZoomViewUtil<View>(mMsgListView); mZoom = new ZoomViewUtil(this); mZoom.setView(mMsgListView, mMsgListAdapter.getTextSize()); } public void onTextResize(float size) { mMsgListAdapter.setTextSize(size); } private void loadDraft() { if (mWorkingMessage != null && mWorkingMessage.isWorthSaving()) { Log.w(TAG, "called with non-empty working message"); return; } if (DEBUG || Log.isLoggable(LogTag.APP, Log.VERBOSE)) { log("call WorkingMessage.loadDraft"); } mWorkingMessage = WorkingMessage.loadDraft(this, mConversation); } private void saveDraft() { // TODO: Do something better here. Maybe make discard() legal // to call twice and make isEmpty() return true if discarded // so it is caught in the clause above this one? if (mWorkingMessage.isDiscarded()) { return; } if (!mWaitingForSubActivity && !mWorkingMessage.isWorthSaving()) { if (LogTag.VERBOSE || DEBUG || Log.isLoggable(LogTag.APP, Log.VERBOSE)) { log("not worth saving, discard WorkingMessage and bail"); } mWorkingMessage.discard(); return; } try { mWorkingMessage.saveDraft(); } catch (ExceedMessageSizeException e) { Log.d(TAG, "Do saveDraft hanppend ExceedMessageSizeException :" + e.toString(), e); String title = this.getResources().getString(R.string.exceed_message_size_limitation); String message = this.getResources().getString(R.string.exceed_message_size_limitation); MessageUtils.showErrorDialog(this, title, message); return; } if (mToastForDraftSave) { Toast.makeText(this, R.string.message_saved_as_draft, Toast.LENGTH_SHORT).show(); } } private boolean isPreparedForSending() { int recipientCount = recipientCount(); return recipientCount > 0 && recipientCount <= MmsConfig.getRecipientLimit() && (mWorkingMessage.hasAttachment() || mWorkingMessage.hasText()); } private int recipientCount() { int recipientCount; // To avoid creating a bunch of invalid Contacts when the recipients // editor is in flux, we keep the recipients list empty. So if the // recipients editor is showing, see if there is anything in it rather // than consulting the empty recipient list. if (isRecipientsEditorVisible()) { recipientCount = mRecipientsEditor.getRecipientCount(); } else { recipientCount = getRecipients().size(); } return recipientCount; } private void sendMessage(boolean bCheckEcmMode) { if (bCheckEcmMode) { // TODO: expose this in telephony layer for SDK build String inEcm = SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE); if (Boolean.parseBoolean(inEcm)) { try { startActivityForResult(new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null), REQUEST_CODE_ECM_EXIT_DIALOG); return; } catch (ActivityNotFoundException e) { // continue to send message Log.e(TAG, "Cannot find EmergencyCallbackModeExitDialog", e); } } } // sunway: get phoneId final String launchMode = getLaunchMode(MMS_LAUNCH_MODE_PATH); if (!mSendingMessage) { if (LogTag.SEVERE_WARNING) { String sendingRecipients = mConversation.getRecipients().serialize(); if (!sendingRecipients.equals(mDebugRecipients)) { String workingRecipients = mWorkingMessage.getWorkingRecipients(); if (!mDebugRecipients.equals(workingRecipients)) { LogTag.warnPossibleRecipientMismatch( "ComposeMessageActivity.sendMessage recipients in " + "window: \"" + mDebugRecipients + "\" differ from recipients from conv: \"" + sendingRecipients + "\" and working recipients: " + workingRecipients, this); } } } int phoneId = TelephonyManager.getDefaultSim(this, TelephonyManager.MODE_MMS); if (phoneId >= 0) { mWorkingMessage.setPhoneId(phoneId); // send can change the recipients. Make sure we remove the listeners first and then add // them back once the recipient list has settled. removeRecipientsListeners(); if (mWorkingMessage.send(mDebugRecipients)) { mSentMessage = true; mSendingMessage = true; addRecipientsListeners(); } else { mSendingMessage = false; } } else { mSimChooserDialg.setListener(new SimChooserDialog.OnSimPickedListener() { public void onSimPicked(int phoneId) { if (phoneId == -1) { return; } mWorkingMessage.setPhoneId(phoneId); // send can change the recipients. Make sure we remove the listeners first and then add // them back once the recipient list has settled. removeRecipientsListeners(); if (mWorkingMessage.send(mDebugRecipients)) { mSentMessage = true; mSendingMessage = true; addRecipientsListeners(); } else { mSendingMessage = false; } if (mExitOnSent || "folder".equals(launchMode)) { ComposeMessageActivity.this.finish(); } } }); mSimChooserDialg.show(); return; } // // send can change the recipients. Make sure we remove the listeners first and then add // // them back once the recipient list has settled. // removeRecipientsListeners(); // mWorkingMessage.send(mDebugRecipients); // mSentMessage = true; // mSendingMessage = true; // addRecipientsListeners(); } // But bail out if we are supposed to exit after the message is sent. if (mExitOnSent || "folder".equals(launchMode)) { finish(); } } private void resetMessage() { if (DEBUG || Log.isLoggable(LogTag.APP, Log.VERBOSE)) { log(""); } // Make the attachment editor hide its view. mAttachmentEditor.hideView(); // Hide the subject editor. showSubjectEditor(false); // Focus to the text editor. mTextEditor.requestFocus(); // We have to remove the text change listener while the text editor gets cleared and // we subsequently turn the message back into SMS. When the listener is listening while // doing the clearing, it's fighting to update its counts and itself try and turn // the message one way or the other. mTextEditor.removeTextChangedListener(mTextEditorWatcher); // Clear the text box. TextKeyListener.clear(mTextEditor.getText()); mWorkingMessage = WorkingMessage.createEmpty(this); mWorkingMessage.setConversation(mConversation); hideRecipientEditor(); drawBottomPanel(); // "Or not", in this case. updateSendButtonState(); // Our changes are done. Let the listener respond to text changes once again. mTextEditor.addTextChangedListener(mTextEditorWatcher); // Close the soft on-screen keyboard if we're in landscape mode so the user can see the // conversation. if (mIsLandscape) { InputMethodManager inputMethodManager = (InputMethodManager) getSystemService( Context.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow(mTextEditor.getWindowToken(), 0); } mLastRecipientCount = 0; mSendingMessage = false; //jinwei if (FeatureSwitch.COMPOSE_MESSAGE_TIP_SUPPORT) { //mTitleRight.setText(LIMITED_MESSAGE_MAX_COUNT + "/" + 1); } } private void updateSendButtonState() { boolean enable = false; if (isPreparedForSending()) { enable = true;//fix for bug 8868 // When the type of attachment is slideshow, we should // also hide the 'Send' button since the slideshow view // already has a 'Send' button embedded. if (!mWorkingMessage.hasSlideshow()) { enable = true; } else { mAttachmentEditor.setCanSend(true); } } else if (null != mAttachmentEditor) { mAttachmentEditor.setCanSend(false); } setSendButtonText(mWorkingMessage.requiresMms()); mSendButton.setEnabled(enable); mSendButton.setFocusable(enable); } private long getMessageDate(Uri uri) { if (uri != null) { Cursor cursor = SqliteWrapper.query(this, mContentResolver, uri, new String[] { Mms.DATE }, null, null, null); if (cursor != null) { try { if ((cursor.getCount() == 1) && cursor.moveToFirst()) { return cursor.getLong(0) * 1000L; } } finally { cursor.close(); } } } return NO_DATE_FOR_DIALOG; } private void initActivityState(Bundle bundle, Intent intent, Bundle bundle2) { if (bundle != null) { String recipients = bundle.getString("recipients"); if (LogTag.VERBOSE) log("get mConversation by recipients " + recipients); mConversation = Conversation.get(this, ContactList.getByNumbers(recipients, false /* don't block */, true /* replace number */), false); addRecipientsListeners(); mExitOnSent = bundle.getBoolean("exit_on_sent", false); mWorkingMessage.readStateFromBundle(bundle); return; } // If we have been passed a thread_id, use that to find our conversation. if (bundle2 != null) { boxmsgThreadId = bundle2.getString("boxmsgThreadId"); } long threadId; if (boxmsgThreadId != null && !"".equals(boxmsgThreadId) && !isLongPressSendFlg) { threadId = Long.parseLong(boxmsgThreadId); } else { threadId = intent.getLongExtra("thread_id", 0); } if (threadId > 0) { if (LogTag.VERBOSE) log("get mConversation by threadId " + threadId); mConversation = Conversation.get(this, threadId, false); } else { Uri intentData = intent.getData(); // mCreate = intent.getBooleanExtra("create", false); if (intentData != null) { // try to get a conversation based on the data URI passed to our intent. if (LogTag.VERBOSE) log("get mConversation by intentData " + intentData); mConversation = Conversation.get(this, intentData, false); // ===== fixed CR<NEWMS00120798> by luning at 2011.11.08 begin ===== String scheme = intentData.getScheme();/*send contact*/ if (scheme != null && scheme.equals("mms")) { String sharePath = intent.getStringExtra("share_contact_uri"); String name = intent.getStringExtra("name"); String detail = intent.getStringExtra("detail"); AssetFileDescriptor fd = null; FileInputStream fis = null; Uri vcardUri = null; try { fd = mContentResolver.openAssetFileDescriptor(Uri.parse(sharePath), "rw"); fis = fd.createInputStream(); File f = new File("/data/data/com.android.mms/" + name + ".vcf"); if (!f.exists()) { f.createNewFile(); } if (!FileUtils.copyToFile(fis, f)) { throw new Exception(); } vcardUri = Uri.fromFile(f); if (null != vcardUri) { // VcardModel vcardModel = new VcardModel(this, // ContentType.TEXT_VCARD, name, vcardUri);????????????? // vcardModel.setDetail(detail); // mWorkingMessage.addVcard(vcardModel);?? this.addAttachment("text/x-vcard", vcardUri, false);//fix for bug 10852 } } catch (Exception e) { Log.e(TAG, "send contact:" + e.toString()); Toast.makeText(ComposeMessageActivity.this, "send sim contact error", Toast.LENGTH_LONG); } finally { try { fis.close(); fd.close(); } catch (Exception e) { Log.e(TAG, "close stream failed" + e.toString()); } } } // ===== fixed CR<NEWMS00120798> by luning at 2011.11.08 end ===== } else { // special intent extra parameter to specify the address String address = intent.getStringExtra("address"); if (!TextUtils.isEmpty(address)) { if (LogTag.VERBOSE) log("get mConversation by address " + address); mConversation = Conversation.get(this, ContactList.getByNumbers(address, false /* don't block */, true /* replace number */), false); } else { if (LogTag.VERBOSE) log("create new conversation"); mConversation = Conversation.createNew(this); } } } addRecipientsListeners(); mExitOnSent = intent.getBooleanExtra("exit_on_sent", false); if (intent.hasExtra("sms_body")) { mWorkingMessage.setText(intent.getStringExtra("sms_body")); } mWorkingMessage.setSubject(intent.getStringExtra("subject"), false); } private void initFocus() { if (!mIsKeyboardOpen) { return; } // If the recipients editor is visible, there is nothing in it, // and the text editor is not already focused, focus the // recipients editor. if (isRecipientsEditorVisible() && TextUtils.isEmpty(mRecipientsEditor.getText()) && !mTextEditor.isFocused()) { mRecipientsEditor.requestFocus(); return; } // If we decided not to focus the recipients editor, focus the text editor. mTextEditor.requestFocus(); } private MessageListAdapter.OnDataSetChangedListener mDataSetChangedListener = new MessageListAdapter.OnDataSetChangedListener() { public void onDataSetChanged(MessageListAdapter adapter) { mPossiblePendingNotification = true; } public void onContentChanged(MessageListAdapter adapter) { // for bug 10942 // When the cursor changes, in the context menu MessageItems has invalid. So close it. ComposeMessageActivity.this.closeContextMenu(); startMsgListQuery(); } }; private void checkPendingNotification() { if (mPossiblePendingNotification && hasWindowFocus()) { Intent intent = getIntent(); Bundle checkbundle = intent.getExtras(); if (checkbundle != null) { boxmsgFlg = checkbundle.getString("boxmsgFlg"); boxmsgThreadId = checkbundle.getString("boxmsgThreadId"); boxmsgMsgId = checkbundle.getString("boxmsgMsgId"); } mConversation.markAsRead(boxmsgFlg, boxmsgThreadId, boxmsgMsgId); mPossiblePendingNotification = false; } } private final class BackgroundQueryHandler extends AsyncQueryHandler { public BackgroundQueryHandler(ContentResolver contentResolver) { super(contentResolver); } @Override protected void onQueryComplete(int token, Object cookie, Cursor cursor) { switch (token) { case MESSAGE_LIST_QUERY_TOKEN: if (ComposeMessageActivity.this.isFinishing()) { Log.d(TAG, "onQueryComplete token:MESSAGE_LIST_QUERY_TOKEN -> isFinishing"); return; } if (mCursor != null) { mCursor.close(); mCursor = null; } int newSelectionPos = -1; long targetMsgId = getIntent().getLongExtra("select_id", -1); if (targetMsgId != -1) { cursor.moveToPosition(-1); while (cursor.moveToNext()) { long msgId = cursor.getLong(COLUMN_ID); if (msgId == targetMsgId) { newSelectionPos = cursor.getPosition(); break; } } } mCursor = cursor; if (mMsgListAdapter != null) { mMsgListAdapter.changeCursor(cursor); } if (newSelectionPos != -1) { mMsgListView.setSelection(newSelectionPos); } // Once we have completed the query for the message history, if // there is nothing in the cursor and we are not composing a new // message, we must be editing a draft in a new conversation (unless // mSentMessage is true). // Show the recipients editor to give the user a chance to add // more people before the conversation begins. if (cursor != null && cursor.getCount() == 0 && !isRecipientsEditorVisible() && !mSentMessage) { if ((INBOX.equals(boxType) || OUTBOX.equals(boxType) || SENT.equals(boxType)) && !outboxEditMsgFlg && !isLongPressSendFlg) { finish(); } else if (OUTBOX.equals(boxType) && outboxEditMsgFlg) { initRecipientsEditor(); //outboxEditMsgFlg = false; } else { initRecipientsEditor(); } } isLongPressSendFlg = false; // FIXME: freshing layout changes the focused view to an unexpected // one, set it back to TextEditor forcely. mTextEditor.requestFocus(); mConversation.blockMarkAsRead(false); return; case ConversationList.HAVE_LOCKED_MESSAGES_TOKEN: long threadId = (Long) cookie; ConversationList.confirmDeleteThreadDialog( new ConversationList.DeleteThreadListener(threadId, mBackgroundQueryHandler, ComposeMessageActivity.this), threadId == -1, cursor != null && cursor.getCount() > 0, ComposeMessageActivity.this); if (cursor != null) { cursor.close(); } break; } } @Override protected void onDeleteComplete(int token, Object cookie, int result) { switch (token) { case DELETE_MESSAGE_TOKEN: case ConversationList.DELETE_CONVERSATION_TOKEN: // Update the notification for new messages since they // may be deleted. MessagingNotification.nonBlockingUpdateNewMessageIndicator(ComposeMessageActivity.this, false, false); // Update the notification for failed messages since they // may be deleted. updateSendFailedNotification(); break; } if ((mMsgListAdapter.getCount() == 1 && !mWorkingMessage.hasText()) || INBOX.equals(boxType) || OUTBOX.equals(boxType) || SENT.equals(boxType)) { finish(); } // If we're deleting the whole conversation, throw away // our current working message and bail. if (token == ConversationList.DELETE_CONVERSATION_TOKEN) { mWorkingMessage.discard(); Conversation.init(ComposeMessageActivity.this, false); finish(); } } } private void showSmileyDialog() { if (mSmileyDialog == null) { int[] icons = SmileyParser.DEFAULT_SMILEY_RES_IDS; String[] names = getResources().getStringArray(SmileyParser.DEFAULT_SMILEY_NAMES); final String[] texts = getResources().getStringArray(SmileyParser.DEFAULT_SMILEY_TEXTS); final int N = names.length; List<Map<String, ?>> entries = new ArrayList<Map<String, ?>>(); for (int i = 0; i < N; i++) { // We might have different ASCII for the same icon, skip it if // the icon is already added. boolean added = false; for (int j = 0; j < i; j++) { if (icons[i] == icons[j]) { added = true; break; } } if (!added) { HashMap<String, Object> entry = new HashMap<String, Object>(); entry.put("icon", icons[i]); entry.put("name", names[i]); entry.put("text", texts[i]); entries.add(entry); } } final SimpleAdapter a = new SimpleAdapter(this, entries, R.layout.smiley_menu_item, new String[] { "icon", "name", "text" }, new int[] { R.id.smiley_icon, R.id.smiley_name, R.id.smiley_text }); SimpleAdapter.ViewBinder viewBinder = new SimpleAdapter.ViewBinder() { public boolean setViewValue(View view, Object data, String textRepresentation) { if (view instanceof ImageView) { Drawable img = getResources().getDrawable((Integer) data); ((ImageView) view).setImageDrawable(img); return true; } return false; } }; a.setViewBinder(viewBinder); AlertDialog.Builder b = new AlertDialog.Builder(this); b.setTitle(getString(R.string.menu_insert_smiley)); b.setCancelable(true); b.setAdapter(a, new DialogInterface.OnClickListener() { @SuppressWarnings("unchecked") public final void onClick(DialogInterface dialog, int which) { HashMap<String, Object> item = (HashMap<String, Object>) a.getItem(which); mTextEditor.append((String) item.get("text")); dialog.dismiss(); } }); mSmileyDialog = b.create(); } mSmileyDialog.show(); } public void onUpdate(final Contact updated) { // Using an existing handler for the post, rather than conjuring up a new one. mMessageListItemHandler.post(new Runnable() { public void run() { ContactList recipients = isRecipientsEditorVisible() ? mRecipientsEditor.constructContactsFromInput() : getRecipients(); if (DEBUG || Log.isLoggable(LogTag.APP, Log.VERBOSE)) { log("[CMA] onUpdate contact updated: " + updated); log("[CMA] onUpdate recipients: " + recipients); } updateTitle(recipients); // The contact information for one (or more) of the recipients has changed. // Rebuild the message list so each MessageItem will get the last contact info. if (recipients != null && recipients.size() > 0) { String number = recipients.get(0).getNumber(); MessageListAdapter.mContact = TextUtils.isEmpty(number) ? "" : Contact.get(number, false).getName(); } ComposeMessageActivity.this.mMsgListAdapter.notifyDataSetChanged(); if (mRecipientsEditor != null) { mRecipientsEditor.populate(recipients); } } }); } private void addRecipientsListeners() { Contact.addListener(this); } private void removeRecipientsListeners() { Contact.removeListener(this); } public static Intent createIntent(Context context, long threadId) { Intent intent = new Intent(context, ComposeMessageActivity.class); if (threadId > 0) { intent.setData(Conversation.getUri(threadId)); } return intent; } private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action.equals(TelephonyIntents.ACTION_IS_SIM_SMS_READY) || action.equals(PhoneFactory.getAction(TelephonyIntents.ACTION_IS_SIM_SMS_READY, 0))) { mSmsReady[0] = intent.getBooleanExtra("isReady", false); Log.d(TAG, "[sms]onReceive ACTION_IS_SIM_SMS_READY mSmsReady[0]=" + mSmsReady[0]); } else if (action.equals(TelephonyIntents.ACTION_IS_SIM_SMS_READY1)) { mSmsReady[1] = intent.getBooleanExtra("isReady", false); Log.d(TAG, "[sms]onReceive ACTION_IS_SIM_SMS_READY1 mSmsReady[1]=" + mSmsReady[1]); } //===== fixed CR<NEWMS00127040> by luning at 11-10-07 begin ===== else if (action.equals("sendMmsReadReport")) { Log.d(TAG, "ComposeMessageActivity receiver sendMmsReadReport action"); HashMap<String, String> map = (HashMap<String, String>) intent .getSerializableExtra("getMmsReadReportData"); if (map != null && map.size() > 0) { MessageUtils.handleReadReport(context, map, PduHeaders.READ_STATUS_READ, null); } } //===== fixed CR<NEWMS00127040> by luning at 11-10-07 end ===== Log.d(TAG, "[sms]onReceive ACTION_IS_SIM_SMS_READY mSmsReady[0]=" + mSmsReady[0]); Log.d(TAG, "[sms]onReceive ACTION_IS_SIM_SMS_READY1 mSmsReady[1]=" + mSmsReady[1]); } }; private String getBody(Uri uri) { if (uri == null) { return null; } String urlStr = uri.getSchemeSpecificPart(); if (!urlStr.contains("?")) { return null; } urlStr = urlStr.substring(urlStr.indexOf('?') + 1); String[] params = urlStr.split("&"); for (String p : params) { if (p.startsWith("body=")) { try { return URLDecoder.decode(p.substring(5), "UTF-8"); } catch (UnsupportedEncodingException e) { } } } return null; } private String getLaunchMode(String filename) { String launchMode = ""; try { File mFile = new File(filename); if (mFile.exists()) { FileInputStream is = new FileInputStream(filename); int length = is.available(); byte buffer[] = new byte[length]; is.read(buffer); launchMode = EncodingUtils.getString(buffer, "UTF-8"); is.close(); } } catch (Exception e) { e.printStackTrace(); } return launchMode; } public void showErDialog() { runOnUiThread(new Runnable() { public void run() { String title = ComposeMessageActivity.this.getResources() .getString(R.string.exceed_message_size_limitation); String message = ComposeMessageActivity.this.getResources() .getString(R.string.exceed_message_size_limitation); MessageUtils.showErrorDialog(ComposeMessageActivity.this, title, message); } }); } public int getTextOldLen() { SlideshowModel slideShow = null; SlideModel slide = null; TextModel text = null; mWorkingMessage.initTextToSlideshow(); slideShow = mWorkingMessage.getSlideshow(); if (slideShow != null) { slide = slideShow.get(0); if (slide != null) { text = slide.getText(); if (text != null) return text.getMediaSize(); } } return 0; } public void updateText(CharSequence s) { SlideshowModel slideShow = null; SlideModel slide = null; TextModel text = null; mWorkingMessage.initTextToSlideshow(); slideShow = mWorkingMessage.getSlideshow(); if (slideShow != null) { slide = slideShow.get(0); if (slide != null) { text = slide.getText(); if (text != null) { slide.updateText(s.toString()); } } } } public int CutByteToMaxLength(byte[] data, int maxByteLen) { int datalen, finallen; byte i, j; byte b; boolean found = false; int[][] headbyte_utf8 = { { 0x80, 0 }, { 0xE0, 0xC0 }, { 0xF0, 0xE0 }, { 0xF8, 0xF0 }, { 0xFC, 0xF8 }, { 0xFE, 0xFC } }; i = j = 0; datalen = data.length; finallen = maxByteLen; while (i < headbyte_utf8.length && i < maxByteLen) { b = data[maxByteLen - 1 - i]; for (j = 0; j < headbyte_utf8.length; j++) { if ((b & headbyte_utf8[j][0]) == headbyte_utf8[j][1]) { if (i == j) { finallen = maxByteLen; } else { finallen = maxByteLen - i - 1; } found = true; break; } } if (found) { break; } i++; } datalen = new String(data, 0, finallen).length(); return datalen; } public void checkMessageSize(CharSequence s, int maxTextLen, int oldLen) { int mmssize = 0; int MaxMmsSize = 0; int textlen = s.length(); byte[] data = s.toString().getBytes(); int datasize = data.length; SlideshowModel slideshow = mWorkingMessage.getSlideshow(); mTxtLength = textlen; mTxtCompareRst = TextCompareResult.NOEXCEED_ANY_SIZE; if (slideshow != null) { mmssize = slideshow.getTotalMsgSizeWithAllHead() - oldLen; MaxMmsSize = MmsConfig.getPduMaxTotalSize(); if (mmssize >= MaxMmsSize) { mTxtLength = 0; mTxtCompareRst = TextCompareResult.EXCEED_ORGINAL_MAX_MMS_SIZE; } else if (textlen > maxTextLen) { s = s.subSequence(0, maxTextLen); data = s.toString().getBytes(); datasize = data.length; mTxtCompareRst = TextCompareResult.EXCEED_MAX_TEXT_SIZE; if (mmssize + datasize > MaxMmsSize) { datasize = MaxMmsSize - mmssize; } mTxtLength = CutByteToMaxLength(data, datasize); } else if (mmssize + datasize > MaxMmsSize) { mTxtCompareRst = TextCompareResult.EXCEED_MAX_MMS_SIZE; datasize = MaxMmsSize - mmssize; mTxtLength = CutByteToMaxLength(data, datasize); } else { mTxtCompareRst = TextCompareResult.NOEXCEED_ANY_SIZE; mTxtLength = textlen; } } else { if (textlen > maxTextLen) { mTxtCompareRst = TextCompareResult.EXCEED_MAX_TEXT_SIZE; mTxtLength = maxTextLen; } else { mTxtCompareRst = TextCompareResult.NOEXCEED_ANY_SIZE; mTxtLength = textlen; } } } private class VcardProgressHandler extends Handler { public VcardProgressHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { mVcardProgressDialog.dismiss(); } } private class myThread extends Thread { private Uri uri; private boolean append; private boolean isAppendMedia = false; public myThread(Uri uri, boolean append) { this.uri = uri; this.append = append; } public myThread(Uri uri, boolean append, boolean isAppendMedia) { this.uri = uri; this.append = append; this.isAppendMedia = isAppendMedia; } @Override public void run() { addVcard(uri, append, isAppendMedia); mEventHandler.handleMessage(null); is_vcard_adding = false; } } private class RotatePictureTask extends AsyncTask<Void, Void, Void> { private Uri pictureUri = null; @Override protected Void doInBackground(Void... params) { Log.d(TAG, "RotatePictureTask doInBackground Enter"); int position = getPositionOfadd(); Log.d(TAG, "RotatePictureTask position == " + position); pictureUri = TempFileProvider.renameScrapFile(".jpg", Integer.toString(position), ComposeMessageActivity.this); Log.d(TAG, "RotatePictureTask doInBackground pictureUri is" + pictureUri); Log.d(TAG, "RotatePictureTask doInBackground Leave"); return null; } @Override protected void onPostExecute(Void result) { Log.d(TAG, "RotatePictureTask onPostExecute Enter"); super.onPostExecute(result); if (pictureUri != null) { Log.d(TAG, "RotatePictureTask onPostExecute pictureUri == " + pictureUri.toString()); addImage(pictureUri, false); } else { Toast.makeText(ComposeMessageActivity.this, R.string.re_take_picture, Toast.LENGTH_SHORT).show(); } Log.d(TAG, "RotatePictureTask onPostExecute Leave"); } } ///////////////////////////////////below by lai//////////////////////////////////////////// /* :Cursor */ private Cursor smsCursor; private void SearchPhoneCursor() { //Uri uri = Uri.parse("content://sms"); // Uri uri = Uri.parse("content://mms-sms/conversations"); // /*liao*/ SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getApplication()); String MmsPhoneNum = preferences.getString("phone_num", ""); String selection = " address <> '" + MmsPhoneNum + "' and address <> '+86" + MmsPhoneNum + "' "; smsCursor = this.managedQuery(uri, new String[] { "thread_id", "address" }, selection, null, "date DESC"); if (smsCursor != null) { if (smsCursor.moveToFirst()) { do { String phn = smsCursor.getString(1); if (phn.equals(mPhoneNumForMms)) { break; } } while (smsCursor.moveToNext()); } } //smsCursor.close(); } /* androidViewTouchEvent 1public boolean dispatchTouchEvent(MotionEvent ev) TouchEvent 2public boolean onInterceptTouchEvent(MotionEvent ev) TouchEventtrueonTouchEvent 3public boolean onTouchEvent(MotionEvent ev) TouchEventComposeMessageActivity.javaonTouchEvent dispatchTouchEvent */ public boolean dispatchTouchEvent(MotionEvent ev) { /*liao*/ if (getIntent().getBooleanExtra("is_forbid_slide", false)) { return super.dispatchTouchEvent(ev); } /*liao*/ int action = ev.getAction(); float x = ev.getX(); float y = ev.getY(); switch (action) { case MotionEvent.ACTION_DOWN: TOUNCH_ACTION_DOWN = true; mStartMotionX = x; break; case MotionEvent.ACTION_MOVE: TOUNCH_ACTION_MOVE = true; break; case MotionEvent.ACTION_UP: SearchPhoneCursor(); mEndMotionX = x; if (TOUNCH_ACTION_DOWN && TOUNCH_ACTION_MOVE) { if ((mEndMotionX - mStartMotionX) > 100) {// if (smsCursor.moveToPrevious()) { startActivity(createIntent(this, smsCursor.getLong(0))); overridePendingTransition(R.anim.in_from_left, R.anim.out_to_right); smsCursor.close();// //finish(); } } else if ((mEndMotionX - mStartMotionX) < -100) {// if (smsCursor.moveToNext()) { startActivity(createIntent(this, smsCursor.getLong(0))); overridePendingTransition(R.anim.in_from_right, R.anim.out_to_left); smsCursor.close();// //finish(); } } } TOUNCH_ACTION_MOVE = false; TOUNCH_ACTION_DOWN = false; break; } return super.dispatchTouchEvent(ev); } /* <activity android:name=".ui.ComposeMessageActivity" android:theme="@/android:style/Theme.NoTitleBar" android:configChanges="orientation|keyboardHidden" android:windowSoftInputMode="stateHidden" android:launchMode="singleTop" > android:launchMode="singleTop" */ private boolean TOUNCH_ACTION_DOWN = false; private boolean TOUNCH_ACTION_MOVE = false; private float mStartMotionX; private float mEndMotionX; ///////////////////////////////////above by lai//////////////////////////////////////////// }