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 17package com.android.messaging.ui.conversationlist; 18 19import android.app.Fragment; 20import android.content.ContentResolver; 21import android.content.Intent; 22import android.media.MediaMetadataRetriever; 23import android.net.Uri; 24import android.os.Bundle; 25import android.text.TextUtils; 26 27import com.android.messaging.Factory; 28import com.android.messaging.datamodel.data.ConversationListItemData; 29import com.android.messaging.datamodel.data.MessageData; 30import com.android.messaging.datamodel.data.PendingAttachmentData; 31import com.android.messaging.ui.BaseBugleActivity; 32import com.android.messaging.ui.UIIntents; 33import com.android.messaging.util.Assert; 34import com.android.messaging.util.ContentType; 35import com.android.messaging.util.LogUtil; 36import com.android.messaging.util.MediaMetadataRetrieverWrapper; 37import com.android.messaging.util.FileUtil; 38 39import java.io.IOException; 40import java.util.ArrayList; 41 42public class ShareIntentActivity extends BaseBugleActivity implements 43 ShareIntentFragment.HostInterface { 44 45 private MessageData mDraftMessage; 46 47 @Override 48 protected void onCreate(final Bundle savedInstanceState) { 49 super.onCreate(savedInstanceState); 50 51 final Intent intent = getIntent(); 52 if (Intent.ACTION_SEND.equals(intent.getAction()) && 53 (!TextUtils.isEmpty(intent.getStringExtra("address")) || 54 !TextUtils.isEmpty(intent.getStringExtra(Intent.EXTRA_EMAIL)))) { 55 // This is really more like a SENDTO intent because a destination is supplied. 56 // It's coming through the SEND intent because that's the intent that is used 57 // when invoking the chooser with Intent.createChooser(). 58 final Intent convIntent = UIIntents.get().getLaunchConversationActivityIntent(this); 59 // Copy the important items from the original intent to the new intent. 60 convIntent.putExtras(intent); 61 convIntent.setAction(Intent.ACTION_SENDTO); 62 convIntent.setDataAndType(intent.getData(), intent.getType()); 63 // We have to fire off the intent and finish before trying to show the fragment, 64 // otherwise we get some flashing. 65 startActivity(convIntent); 66 finish(); 67 return; 68 } 69 new ShareIntentFragment().show(getFragmentManager(), "ShareIntentFragment"); 70 } 71 72 @Override 73 public void onAttachFragment(final Fragment fragment) { 74 final Intent intent = getIntent(); 75 final String action = intent.getAction(); 76 if (Intent.ACTION_SEND.equals(action)) { 77 final Uri contentUri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM); 78 final String contentType = extractContentType(contentUri, intent.getType()); 79 if (LogUtil.isLoggable(LogUtil.BUGLE_TAG, LogUtil.DEBUG)) { 80 LogUtil.d(LogUtil.BUGLE_TAG, String.format( 81 "onAttachFragment: contentUri=%s, intent.getType()=%s, inferredType=%s", 82 contentUri, intent.getType(), contentType)); 83 } 84 if (ContentType.TEXT_PLAIN.equals(contentType)) { 85 final String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT); 86 if (sharedText != null) { 87 mDraftMessage = MessageData.createSharedMessage(sharedText); 88 } else { 89 mDraftMessage = null; 90 } 91 } else if (ContentType.isImageType(contentType) || 92 ContentType.isVCardType(contentType) || 93 ContentType.isAudioType(contentType) || 94 ContentType.isVideoType(contentType)) { 95 if (contentUri != null) { 96 mDraftMessage = MessageData.createSharedMessage(null); 97 addSharedImagePartToDraft(contentType, contentUri); 98 } else { 99 mDraftMessage = null; 100 } 101 } else { 102 // Unsupported content type. 103 Assert.fail("Unsupported shared content type for " + contentUri + ": " + contentType 104 + " (" + intent.getType() + ")"); 105 } 106 } else if (Intent.ACTION_SEND_MULTIPLE.equals(action)) { 107 final String contentType = intent.getType(); 108 if (ContentType.isImageType(contentType)) { 109 // Handle sharing multiple images. 110 final ArrayList<Uri> imageUris = intent.getParcelableArrayListExtra( 111 Intent.EXTRA_STREAM); 112 if (imageUris != null && imageUris.size() > 0) { 113 mDraftMessage = MessageData.createSharedMessage(null); 114 for (final Uri imageUri : imageUris) { 115 final String actualContentType = extractContentType(imageUri, contentType); 116 addSharedImagePartToDraft(actualContentType, imageUri); 117 } 118 } else { 119 mDraftMessage = null; 120 } 121 } else { 122 // Unsupported content type. 123 Assert.fail("Unsupported shared content type: " + contentType); 124 } 125 } else { 126 // Unsupported action. 127 Assert.fail("Unsupported action type for sharing: " + action); 128 } 129 } 130 131 private static String extractContentType(final Uri uri, final String contentType) { 132 if (uri == null) { 133 return contentType; 134 } 135 // First try looking at file extension. This is less reliable in some ways but it's 136 // recommended by 137 // https://developer.android.com/training/secure-file-sharing/retrieve-info.html 138 // Some implementations of MediaMetadataRetriever get things horribly 139 // wrong for common formats such as jpeg (reports as video/ffmpeg) 140 final ContentResolver resolver = Factory.get().getApplicationContext().getContentResolver(); 141 final String typeFromExtension = resolver.getType(uri); 142 if (typeFromExtension != null) { 143 return typeFromExtension; 144 } 145 final MediaMetadataRetrieverWrapper retriever = new MediaMetadataRetrieverWrapper(); 146 try { 147 retriever.setDataSource(uri); 148 final String extractedType = retriever.extractMetadata( 149 MediaMetadataRetriever.METADATA_KEY_MIMETYPE); 150 if (extractedType != null) { 151 return extractedType; 152 } 153 } catch (final IOException e) { 154 LogUtil.i(LogUtil.BUGLE_TAG, "Could not determine type of " + uri, e); 155 } finally { 156 retriever.release(); 157 } 158 return contentType; 159 } 160 161 private void addSharedImagePartToDraft(final String contentType, final Uri imageUri) { 162 if (FileUtil.isInPrivateDir(imageUri)) { 163 Assert.fail("Cannot send private file " + imageUri.toString()); 164 } else { 165 mDraftMessage.addPart(PendingAttachmentData.createPendingAttachmentData(contentType, 166 imageUri)); 167 } 168 } 169 170 @Override 171 public void onConversationClick(final ConversationListItemData conversationListItemData) { 172 UIIntents.get().launchConversationActivity( 173 this, conversationListItemData.getConversationId(), mDraftMessage); 174 finish(); 175 } 176 177 @Override 178 public void onCreateConversationClick() { 179 UIIntents.get().launchCreateNewConversationActivity(this, mDraftMessage); 180 finish(); 181 } 182} 183