6.0联系人跳转到短信的逻辑

来源:互联网 发布:七天网络阅卷登录 编辑:程序博客网 时间:2024/05/30 22:43

Android 6.0中其他app跳转到messaging后,按back键无法返回原应用,分析了下原因,原来是处在messaging的启动方式上。
在Android 6.0中联系人的详情统一为了QuickContactActivity,乍看里面内容很多、很杂,整理了下,发现主要是onCreate里的这几个自定义的ExpandingEntryCardView。

@Override    protected void onCreate(Bundle savedInstanceState) {        ……………………        mContactCard = (ExpandingEntryCardView) findViewById(R.id.communication_card);        mNoContactDetailsCard = (ExpandingEntryCardView) findViewById(R.id.no_contact_data_card);        mRecentCard = (ExpandingEntryCardView) findViewById(R.id.recent_card);        mAboutCard = (ExpandingEntryCardView) findViewById(R.id.about_card);        ……………………    }

跳转到短信,必然是有点击事件的,这些内容和上面的代码一样都是在onCreate中:

mNoContactDetailsCard.setOnClickListener(mEntryClickHandler);mContactCard.setOnClickListener(mEntryClickHandler);mContactCard.setExpandButtonText(        getResources().getString(R.string.expanding_entry_card_view_see_all));        mContactCard.setOnCreateContextMenuListener(mEntryContextMenuListener);mRecentCard.setOnClickListener(mEntryClickHandler);        mRecentCard.setTitle(getResources().getString(R.string.recent_card_title));mAboutCard.setOnClickListener(mEntryClickHandler);        mAboutCard.setOnCreateContextMenuListener(mEntryContextMenuListener);

跳转逻辑就在这个mEntryClickHandler中:

final OnClickListener mEntryClickHandler = new OnClickListener() {        @Override        public void onClick(View v) {            final Object entryTagObject = v.getTag();            if (entryTagObject == null || !(entryTagObject instanceof EntryTag)) {                Log.w(TAG, "EntryTag was not used correctly");                return;            }            final EntryTag entryTag = (EntryTag) entryTagObject;            final Intent intent = entryTag.getIntent();            final int dataId = entryTag.getId();            if (dataId == CARD_ENTRY_ID_EDIT_CONTACT) {                editContact();                return;            }            //?????            //intent.setAction(Intent.ACTION_DIAL);            //-----------------------------------//            // Pass the touch point through the intent for use in the InCallUI            if (Intent.ACTION_CALL.equals(intent.getAction())) {                if (TouchPointManager.getInstance().hasValidPoint()) {                    Bundle extras = new Bundle();                    extras.putParcelable(TouchPointManager.TOUCH_POINT,                            TouchPointManager.getInstance().getPoint());                    intent.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, extras);                }            }            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);            mHasIntentLaunched = true;            try {                startActivity(intent);            } catch (SecurityException ex) {                Toast.makeText(QuickContactActivity.this, R.string.missing_app,                        Toast.LENGTH_SHORT).show();                Log.e(TAG, "QuickContacts does not have permission to launch "                        + intent);            } catch (ActivityNotFoundException ex) {                Toast.makeText(QuickContactActivity.this, R.string.missing_app,                        Toast.LENGTH_SHORT).show();            }            // Default to USAGE_TYPE_CALL. Usage is summed among all types for sorting each data id            // so the exact usage type is not necessary in all cases            String usageType = DataUsageFeedback.USAGE_TYPE_CALL;            final Uri intentUri = intent.getData();            if ((intentUri != null && intentUri.getScheme() != null &&                    intentUri.getScheme().equals(ContactsUtils.SCHEME_SMSTO)) ||                    (intent.getType() != null && intent.getType().equals(MIMETYPE_SMS))) {                usageType = DataUsageFeedback.USAGE_TYPE_SHORT_TEXT;            }            // Data IDs start at 1 so anything less is invalid            if (dataId > 0) {                final Uri dataUsageUri = DataUsageFeedback.FEEDBACK_URI.buildUpon()                        .appendPath(String.valueOf(dataId))                        .appendQueryParameter(DataUsageFeedback.USAGE_TYPE, usageType)                        .build();                try {                    final boolean successful = getContentResolver().update(                            dataUsageUri, new ContentValues(), null, null) > 0;                    if (!successful) {                        Log.w(TAG, "DataUsageFeedback increment failed");                    }                } catch (SecurityException ex) {                    Log.w(TAG, "DataUsageFeedback increment failed", ex);                }            } else {                Log.w(TAG, "Invalid Data ID");            }        }    };

在onClick中,intent的获取是通过view -> getTag -> getIntent来获取的。发送短信这个button对应view获取到的intent的action自然为ACTION_SENDTO,这个action是会由默认的短信应用来处理的。在Android 6.0中,我们将老旧的Mms替换为了messaging,因此被启动的activity为LaunchConversationActivity,到了这里就开始有趣了。
本来我以为这个activity就是编辑短信并发送的activity,查看源码发现其仅有区区137行代码,而且还在onCreate中把自己finish了!?!

@Override    protected void onCreate(final Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        if (UiUtils.redirectToPermissionCheckIfNeeded(this)) {            return;        }        final Intent intent = getIntent();        final String action = intent.getAction();        if (Intent.ACTION_SENDTO.equals(action) || Intent.ACTION_VIEW.equals(action)) {            String[] recipients = UriUtil.parseRecipientsFromSmsMmsUri(intent.getData());            final boolean haveAddress = !TextUtils.isEmpty(intent.getStringExtra(ADDRESS));            final boolean haveEmail = !TextUtils.isEmpty(intent.getStringExtra(Intent.EXTRA_EMAIL));            if (recipients == null && (haveAddress || haveEmail)) {                if (haveAddress) {                    recipients = new String[] { intent.getStringExtra(ADDRESS) };                } else {                    recipients = new String[] { intent.getStringExtra(Intent.EXTRA_EMAIL) };                }            }            mSmsBody = intent.getStringExtra(SMS_BODY);            if (TextUtils.isEmpty(mSmsBody)) {                // Used by intents sent from the web YouTube (and perhaps others).                mSmsBody = getBody(intent.getData());                if (TextUtils.isEmpty(mSmsBody)) {                    // If that fails, try yet another method apps use to share text                    if (ContentType.TEXT_PLAIN.equals(intent.getType())) {                        mSmsBody = intent.getStringExtra(Intent.EXTRA_TEXT);                    }                }            }            if (recipients != null) {                mBinding.bind(DataModel.get().createLaunchConversationData(this));                mBinding.getData().getOrCreateConversation(mBinding, recipients);            } else {                // No recipients were specified in the intent.                // Start a new conversation with contact picker. The new conversation will be                // primed with the (optional) message in mSmsBody.                onGetOrCreateNewConversation(null);            }        } else {            LogUtil.w(LogUtil.BUGLE_TAG, "Unsupported conversation intent action : " + action);        }        // As of M, activities without a visible window must finish before onResume completes.        finish();    }

原来这是一个没有UI的activity,它的作用就是启动ConversationActivity,启动代码如下:

    @Override    public void onGetOrCreateNewConversation(final String conversationId) {        final Context context = Factory.get().getApplicationContext();                                                            UIIntents.get().launchConversationActivityWithParentStack(context, conversationId, mSmsBody);    }

launchConversationActivityWithParentStack就是这个方法导致了back无法退回,其实现在UIIntentsImpl.java中:

@Override    public void launchConversationActivityWithParentStack(final Context context,                final String conversationId, final String smsBody) {        final MessageData messageData = TextUtils.isEmpty(smsBody)                ? null                : MessageData.createDraftSmsMessage(conversationId, null, smsBody);        TaskStackBuilder.create(context)                .addNextIntentWithParentStack(                        getConversationActivityIntent(context, conversationId, messageData,                                false /* withCustomTransition */))                .startActivities();    }

做过通知栏的朋友可能很早就猜到原因了,就是TaskStackBuilder设置了回退栈的内容,虽然这是在Android 4.1就引入了的内容,以前还真没遇到:

 <activity            android:name=".ui.conversation.ConversationActivity"            android:configChanges="orientation|screenSize|keyboardHidden"            android:screenOrientation="user"            android:windowSoftInputMode="stateHidden|adjustResize"            android:theme="@style/BugleTheme.ConversationActivity"            android:parentActivityName="com.android.messaging.ui.conversationlist.ConversationListActivity">            <meta-data                android:name="android.support.PARENT_ACTIVITY"                android:value="com.android.messaging.ui.conversationlist.ConversationListActivity" />        </activity>

parentActivityName设置为了ConversationListActivity. So,只要回退,肯定是回到短信列表页面。

0 0
原创粉丝点击