1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.messaging.ui.conversation;
18 
19 import android.app.Activity;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.net.Uri;
23 import android.os.Bundle;
24 import android.text.TextUtils;
25 
26 import com.android.messaging.Factory;
27 import com.android.messaging.R;
28 import com.android.messaging.datamodel.DataModel;
29 import com.android.messaging.datamodel.binding.Binding;
30 import com.android.messaging.datamodel.binding.BindingBase;
31 import com.android.messaging.datamodel.data.LaunchConversationData;
32 import com.android.messaging.ui.UIIntents;
33 import com.android.messaging.util.ContentType;
34 import com.android.messaging.util.LogUtil;
35 import com.android.messaging.util.UiUtils;
36 import com.android.messaging.util.UriUtil;
37 
38 import java.io.UnsupportedEncodingException;
39 import java.net.URLDecoder;
40 import java.util.ArrayList;
41 import java.util.List;
42 
43 /**
44  * Launches ConversationActivity for sending a message to, or viewing messages from, a specific
45  * recipient.
46  * <p>
47  * (This activity should be marked noHistory="true" in AndroidManifest.xml)
48  */
49 public class LaunchConversationActivity extends Activity implements
50         LaunchConversationData.LaunchConversationDataListener {
51     private static final int MAX_RECIPIENT_LENGTH = 100;
52     static final String SMS_BODY = "sms_body";
53     static final String ADDRESS = "address";
54     final Binding<LaunchConversationData> mBinding = BindingBase.createBinding(this);
55     String mSmsBody;
56 
57     @Override
onCreate(final Bundle savedInstanceState)58     protected void onCreate(final Bundle savedInstanceState) {
59         super.onCreate(savedInstanceState);
60         if (UiUtils.redirectToPermissionCheckIfNeeded(this)) {
61             return;
62         }
63 
64         final Intent intent = getIntent();
65         final String action = intent.getAction();
66         if (Intent.ACTION_SENDTO.equals(action) || Intent.ACTION_VIEW.equals(action)) {
67             String[] recipients = null;
68             final String commaSeparatedRecipients =
69                     UriUtil.parseRecipientsFromSmsMmsUri(intent.getData());
70             if (commaSeparatedRecipients != null) {
71                 recipients = commaSeparatedRecipients.split(",");
72             }
73             final boolean haveAddress = !TextUtils.isEmpty(intent.getStringExtra(ADDRESS));
74             final boolean haveEmail = !TextUtils.isEmpty(intent.getStringExtra(Intent.EXTRA_EMAIL));
75             if (recipients == null && (haveAddress || haveEmail)) {
76                 if (haveAddress) {
77                     recipients = new String[] { intent.getStringExtra(ADDRESS) };
78                 } else {
79                     recipients = new String[] { intent.getStringExtra(Intent.EXTRA_EMAIL) };
80                 }
81             }
82             if (recipients != null) {
83                 recipients = trimInvalidRecipients(recipients);
84             }
85             mSmsBody = intent.getStringExtra(SMS_BODY);
86             if (TextUtils.isEmpty(mSmsBody)) {
87                 // Used by intents sent from the web YouTube (and perhaps others).
88                 mSmsBody = getBody(intent.getData());
89                 if (TextUtils.isEmpty(mSmsBody)) {
90                     // If that fails, try yet another method apps use to share text
91                     if (ContentType.TEXT_PLAIN.equals(intent.getType())) {
92                         mSmsBody = intent.getStringExtra(Intent.EXTRA_TEXT);
93                     }
94                 }
95             }
96             if (recipients != null) {
97                 mBinding.bind(DataModel.get().createLaunchConversationData(this));
98                 mBinding.getData().getOrCreateConversation(mBinding, recipients);
99             } else {
100                 // No recipients were specified in the intent.
101                 // Start a new conversation with contact picker. The new conversation will be
102                 // primed with the (optional) message in mSmsBody.
103                 onGetOrCreateNewConversation(null);
104             }
105         } else {
106             LogUtil.w(LogUtil.BUGLE_TAG, "Unsupported conversation intent action : " + action);
107         }
108         // As of M, activities without a visible window must finish before onResume completes.
109         finish();
110     }
111 
trimInvalidRecipients(String[] recipients)112     private String[] trimInvalidRecipients(String[] recipients) {
113         List<String> trimmedRecipients = new ArrayList<>();
114         for (String recipient : recipients) {
115             if (recipient.length() < MAX_RECIPIENT_LENGTH) {
116                 trimmedRecipients.add(recipient);
117             }
118         }
119         if (trimmedRecipients.size() > 0) {
120             return trimmedRecipients.toArray(new String[0]);
121         } else {
122             return null;
123         }
124     }
125 
getBody(final Uri uri)126     private String getBody(final Uri uri) {
127         if (uri == null) {
128             return null;
129         }
130         String urlStr = uri.getSchemeSpecificPart();
131         if (!urlStr.contains("?")) {
132             return null;
133         }
134         urlStr = urlStr.substring(urlStr.indexOf('?') + 1);
135         final String[] params = urlStr.split("&");
136         for (final String p : params) {
137             if (p.startsWith("body=")) {
138                 try {
139                     return URLDecoder.decode(p.substring(5), "UTF-8");
140                 } catch (final UnsupportedEncodingException e) {
141                     // Invalid URL, ignore
142                 }
143             }
144         }
145         return null;
146     }
147 
148     @Override
onGetOrCreateNewConversation(final String conversationId)149     public void onGetOrCreateNewConversation(final String conversationId) {
150         final Context context = Factory.get().getApplicationContext();
151         UIIntents.get().launchConversationActivityWithParentStack(context, conversationId,
152                 mSmsBody);
153     }
154 
155     @Override
onGetOrCreateNewConversationFailed()156     public void onGetOrCreateNewConversationFailed() {
157         UiUtils.showToastAtBottom(R.string.conversation_creation_failure);
158     }
159 }
160