首页 > 代码库 > 解决:长按一条接收到的彩信,快捷菜单“选择性复制”功能错误

解决:长按一条接收到的彩信,快捷菜单“选择性复制”功能错误

【测试步骤】长按一条接收到的彩信,快捷菜单——“选择性复制”
【测试结果】功能错误,未实现选择性复制,实际是播放彩信内容

【预期结果】应该选择复制彩信内容

通过分析代码我们定位到以下代码:

    private final class MsgListMenuClickListener implements MenuItem.OnMenuItemClickListener {
        private MessageItem mMsgItem;

        public MsgListMenuClickListener(MessageItem msgItem) {
            mMsgItem = msgItem;
        }

        @Override
        public boolean onMenuItemClick(MenuItem item) {
            if (mMsgItem == null) {
                return false;
            }

        ......

                case MENU_SELECT_COPY_MESSAGE_TEXT:

                    AdapterView.AdapterContextMenuInfo info;
                    try {
                         info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
                    } catch (ClassCastException exception) {
                        Log.e(TAG, "Bad menuInfo.", exception);
                        return false;
                    }

                    final Cursor cursor = (Cursor) mMsgListAdapter.getItem(info.position);
                    if (mMsgItem.isSms()) {
                        showSmsMessageContent(cursor);
                    } else {
                        MessageUtils.viewMmsMessageAttachment(ComposeMessageActivity.this,
                                ContentUris.withAppendedId(Mms.CONTENT_URI, mMsgItem.mMsgId), null,
                                getAsyncDialog());
                    }

                    return true;

        ......

    }

通过对以上代码我们发现,这里对彩信和短信分别进行了处理,在接着追踪代码时我们发现,如果信息为短信则现实短信的详细信息包括发件人,发件时间等,如果信息为彩信则直接进入彩信幻灯片播放界面,并播放幻灯片。与选项描述和原始业务逻辑相违背,因此作出一下修改。

我们只提取信息的文本,如果信息为彩信,并且彩信只有附件,则屏蔽该选项(Select text to copy)。

因此作出以下修改:

修改ComposeMessageActivity文件中, OnCreateContextMenuListener子类中onCreateContextMenu()方法。

这是修改前的源文件:

            ......

            // Forward is not available for undownloaded messages.
            if (msgItem.isDownloaded() && (msgItem.isSms() || msgItem.mIsForwardable)) {
                menu.add(0, MENU_FORWARD_MESSAGE, 0, R.string.menu_forward)
                        .setOnMenuItemClickListener(l);
            }

            if (!msgItem.isMms() || msgItem.isDownloaded()) {
                menu.add(0, MENU_SELECT_COPY_MESSAGE_TEXT, 0, R.string.select_copy_message_text)
                        .setOnMenuItemClickListener(l);
            }


            //only failed send message have resend function
            if (msgItem.isFailedMessage()) {
                    menu.add(0, MENU_RESEND, 0, R.string.menu_resend)
                            .setOnMenuItemClickListener(l);
            }

            ......

下面是修改后的源代码:(将上述代码中蓝色加粗代码修改为下面红色加粗代码)



            ......

            // Forward is not available for undownloaded messages.
            if (msgItem.isDownloaded() && (msgItem.isSms() || msgItem.mIsForwardable)) {
                menu.add(0, MENU_FORWARD_MESSAGE, 0, R.string.menu_forward)
                        .setOnMenuItemClickListener(l);
            }


            String selectText=null;
            selectText=msgItem.mBody;
            if( (!msgItem.isMms() || msgItem.isDownloaded())&&(selectText!=null)){
                menu.add(0, MENU_SELECT_COPY_MESSAGE_TEXT, 0, R.string.select_copy_message_text)
                        .setOnMenuItemClickListener(l);
            }

            //only failed send message have resend function
            if (msgItem.isFailedMessage()) {
                    menu.add(0, MENU_RESEND, 0, R.string.menu_resend)
                            .setOnMenuItemClickListener(l);
            }

            ......


添加SelectTextToCopyActivity文件,该类为对信息文本内容进行自由复制操作界面:

package com.android.mms.ui;

import java.util.ArrayList;

import android.app.ActionBar;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.ActivityNotFoundException;
import android.content.AsyncQueryHandler;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SqliteWrapper;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.provider.ContactsContract;
import android.provider.ContactsContract.Contacts;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.provider.Telephony.Mms;
import android.provider.Telephony.Sms;
import android.telephony.PhoneNumberUtils;
import android.text.method.HideReturnsTransformationMethod;
import android.text.style.URLSpan;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.view.GestureDetector;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.util.Log;
import android.util.TypedValue;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import android.widget.Toast;

import com.android.mms.data.Contact;
import com.android.mms.LogTag;
import com.android.mms.R;
import com.android.mms.transaction.MessageSender;
import com.android.mms.transaction.MessagingNotification;
import com.android.mms.transaction.SmsMessageSender;
import com.android.mms.ui.MessageUtils;
import com.android.mms.ui.WwwContextMenuActivity;
import com.android.mms.util.SmileyParser;
import com.google.android.mms.MmsException;

public class SelectTextToCopyActivity extends Activity {
    private static final String TAG = "SelectTextToCopyActivity";
    private String mMsgText;// Text of message

    private TextView mBodyTextView;
    private float mScaleFactor = 1;
    private  ScaleGestureDetector mScaleDetector;
    private  GestureDetector mGestureDetector;

    private static final int ZOOM_IN = 4;
    private static final int ZOOM_OUT = 5;
    private final int MAX_ZOOM_IN_SIZE = 60;
    private final int MAX_ZOOM_OUT_SIZE = 20;
    private final int THE_SIZE_OF_PER_ZOOM = 9;
    private float mTextSize = 27;
    private int mZoomMsg = -1;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
        setContentView(R.layout.activity_select_text_to_copy);
        getIntentData();
        initUi();
    }

    @Override
    public boolean onSearchRequested() {
        return false;
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                finish();
                break;
        }
        return true;
    }


    private void getIntentData() {
        Intent intent = getIntent();
        mMsgText = intent.getStringExtra("select");
    }

    private void initUi() {
        mBodyTextView = (TextView) findViewById(R.id.text_select);
        mBodyTextView.setTransformationMethod(HideReturnsTransformationMethod.getInstance());
        mBodyTextView.setTextIsSelectable(true);
        mBodyTextView.setText(formatMessage(mMsgText));
        mBodyTextView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onMailBoxMessageClick(SelectTextToCopyActivity.this);
            }
        });
        mScaleDetector = new ScaleGestureDetector(this, new MyScaleListener());
        mGestureDetector = new GestureDetector(this,
                new GestureDetector.SimpleOnGestureListener(){ });
        mGestureDetector.setOnDoubleTapListener(null);
        ActionBar actionBar = getActionBar();
        actionBar.setDisplayHomeAsUpEnabled(true);
    }

    public void onMailBoxMessageClick(final Context context) {
        // Check for links. If none, do nothing; if 1, open it; if >1, ask user
        // to pick one
        final URLSpan[] spans = mBodyTextView.getUrls();
        if (spans.length == 1) {
            String url = spans[0].getURL();
            if (MessageUtils.isWebUrl(url)) {
                Uri uri = Uri.parse(url);
                Intent intent = new Intent(context, WwwContextMenuActivity.class);
                intent.setData(uri);
                context.startActivity(intent);
            } else {
                final String telPrefix = "tel:";
                if (url.startsWith(telPrefix)) {
                    url = url.substring(telPrefix.length());
                }
                if (PhoneNumberUtils.isWellFormedSmsAddress(url)) {
                    MessageUtils.showNumberOptions(this, url);
                } else {
                    spans[0].onClick(mBodyTextView);
                }
            }
        } else if (spans.length > 1) {
            ArrayAdapter<URLSpan> adapter = new ArrayAdapter<URLSpan>(context,
                    android.R.layout.select_dialog_item, spans) {

                @Override
                public View getView(int position, View convertView, ViewGroup parent) {
                    View v = super.getView(position, convertView, parent);
                    try {
                        URLSpan span = getItem(position);
                        String url = span.getURL();
                        Uri uri = Uri.parse(url);
                        TextView tv = (TextView) v;
                        Drawable d = context.getPackageManager().getActivityIcon(
                                new Intent(Intent.ACTION_VIEW, uri));
                        if (d != null) {
                            d.setBounds(0, 0, d.getIntrinsicHeight(),
                                    d.getIntrinsicHeight());
                            tv.setCompoundDrawablePadding(10);
                            tv.setCompoundDrawables(d, null, null, null);
                        }
                        // If prefix string is "mailto" then translate
                        // it.
                        final String mailPrefix = "mailto:";
                        String tmpUrl = null;
                        if (url != null) {
                            if (url.startsWith(mailPrefix)) {
                                url = context.getResources().getString(R.string.mail_to) +
                                        url.substring(mailPrefix.length());
                            }
                            tmpUrl = url.replaceAll("tel:", "");
                        }
                        tv.setText(tmpUrl);
                    } catch (android.content.pm.PackageManager.NameNotFoundException ex) {
                        // it‘s ok if we‘re unable to set the drawable
                        // for this view - the user
                        // can still use it
                    }
                    return v;
                }
            };

            AlertDialog.Builder b = new AlertDialog.Builder(context);

            DialogInterface.OnClickListener click = new DialogInterface.OnClickListener() {
                @Override
                public final void onClick(DialogInterface dialog, int which) {
                    if (which >= 0) {
                        String url = spans[which].getURL();
                        if (MessageUtils.isWebUrl(url)) {
                            Uri uri = Uri.parse(url);
                            Intent intent = new Intent(SelectTextToCopyActivity.this,
                                    WwwContextMenuActivity.class);
                            intent.setData(uri);
                            context.startActivity(intent);
                        } else {
                            final String telPrefix = "tel:";
                            if (url.startsWith(telPrefix)) {
                                url = url.substring(telPrefix.length());
                            }
                            if (PhoneNumberUtils.isWellFormedSmsAddress(url)) {
                                MessageUtils.showNumberOptions(context, url);
                            } else {
                                spans[which].onClick(mBodyTextView);
                            }
                        }
                    }
                    dialog.dismiss();
                }
            };

            b.setTitle(R.string.select_link_title);
            b.setCancelable(true);
            b.setAdapter(adapter, click);

            b.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
                @Override
                public final void onClick(DialogInterface dialog, int which) {
                    dialog.dismiss();
                }
            });

            b.show();
        }
    }

    private Handler mUiHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case ZOOM_IN:
                 zoomIn();
                 mBodyTextView.invalidate();
                 break;
            case ZOOM_OUT:
                 zoomOut();
                 mBodyTextView.invalidate();
                 break;
            default:
                break;
            }
        }
    };

    private void zoomIn() {
        mTextSize = mTextSize + THE_SIZE_OF_PER_ZOOM <= MAX_ZOOM_IN_SIZE ?
                mTextSize + THE_SIZE_OF_PER_ZOOM : MAX_ZOOM_IN_SIZE;
        if (mTextSize >= MAX_ZOOM_IN_SIZE) {
            mTextSize = MAX_ZOOM_IN_SIZE;
        }
        mBodyTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX,mTextSize);
    }

    private void zoomOut() {
        mTextSize = mTextSize - THE_SIZE_OF_PER_ZOOM < MAX_ZOOM_OUT_SIZE ?
                MAX_ZOOM_OUT_SIZE : mTextSize - THE_SIZE_OF_PER_ZOOM;
        if (mTextSize <= MAX_ZOOM_OUT_SIZE) {
           mTextSize = MAX_ZOOM_OUT_SIZE;
        }
        mBodyTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX,mTextSize);
    }

    private class MyScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            float scale = detector.getScaleFactor();
            if (scale < 0.999999 || scale > 1.00001) {
                mScaleFactor = scale;
            }
            return true;
        }

        @Override
        public boolean onScaleBegin(ScaleGestureDetector detector) {
            return true;
        }

        @Override
        public void onScaleEnd(ScaleGestureDetector detector) {
            float scale = detector.getScaleFactor();
            if (mScaleFactor > 1.0) {
                mZoomMsg = ZOOM_IN;
            } else if (mScaleFactor < 1.0) {
                mZoomMsg = ZOOM_OUT;
            }
        }
    }

    public boolean onInterceptTouchEvent(MotionEvent ev) {
        mScaleDetector.onTouchEvent(ev);
        final int action = ev.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                mGestureDetector.onTouchEvent(ev);
                return false;

            case MotionEvent.ACTION_MOVE:
               mGestureDetector.onTouchEvent(ev);
               return false;

            case MotionEvent.ACTION_UP:
                mGestureDetector.onTouchEvent(ev);
                Message msg = Message.obtain();
                msg.what = mZoomMsg;
                mUiHandler.sendMessage(msg);
                mZoomMsg = -1;
                return false;
        }
        return true;
    }

    public boolean onTouchEvent(MotionEvent ev) {
        mScaleDetector.onTouchEvent(ev);
        final int action = ev.getAction();

        switch (action) {
            case MotionEvent.ACTION_DOWN:
                mGestureDetector.onTouchEvent(ev);
               return true;

            case MotionEvent.ACTION_MOVE:
               mGestureDetector.onTouchEvent(ev);
               return true;

            case MotionEvent.ACTION_UP:
                mGestureDetector.onTouchEvent(ev);
                Message msg = Message.obtain();
                msg.what = mZoomMsg;
                mUiHandler.sendMessage(msg);
                mZoomMsg = -1;
                return true;

            case MotionEvent.ACTION_CANCEL:
                mGestureDetector.onTouchEvent(ev);
                return true;

            default:
                if (mGestureDetector.onTouchEvent(ev)) {
                    return true;
                }

           return true;
        }
    }

    private CharSequence formatMessage(String body) {
        SpannableStringBuilder buf = new SpannableStringBuilder();
        if (!TextUtils.isEmpty(body)) {
            SmileyParser parser = SmileyParser.getInstance();
            buf.append(parser.addSmileySpans(body));
        }
        return buf;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mUiHandler.removeCallbacksAndMessages(null);
    }
}


添加activity_select_text_to_copy.xml文件,为相对应布局文件:

<?xml version="1.0" encoding="utf-8"?>

<!-- AddBy:yabin.huang BugID:SWBUG00030439 Date:20140626 -->

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/outlayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white"
    android:gravity="center_horizontal"
    android:isScrollContainer="true"
    android:orientation="vertical" >

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:minHeight="50dip"
                android:orientation="vertical" >

                <TextView
                    android:id="@+id/text_select"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:autoLink="all"
                    android:linksClickable="false"
                    android:padding="20dp"
                    android:textColor="#000000"
                    android:textSize="18dip" />
            </LinearLayout>

</LinearLayout>

并在清单文件中对Activity进行注册:

        <activity android:name=".ui.SelectTextToCopyActivity"
            android:label="@string/select_copy_message_text"
            android:theme="@style/MmsHoloTheme"
            android:configChanges="orientation|screenSize|keyboardHidden"
            android:launchMode="singleTop" >
        </activity>


OK!问题得到解决。