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