• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 package com.android.messaging.ui.mediapicker;
17 
18 import android.app.Fragment;
19 import android.content.Intent;
20 import android.net.Uri;
21 import android.os.Bundle;
22 
23 import com.android.messaging.Factory;
24 import com.android.messaging.datamodel.data.PendingAttachmentData;
25 import com.android.messaging.ui.UIIntents;
26 import com.android.messaging.util.LogUtil;
27 import com.android.messaging.util.FileUtil;
28 import com.android.messaging.util.ImageUtils;
29 import com.android.messaging.util.SafeAsyncTask;
30 
31 /**
32  * Wraps around the functionalities to allow the user to pick an image/video/audio from the document
33  * picker. Instances of this class must be tied to a Fragment which is able to delegate activity
34  * result callbacks.
35  */
36 public class DocumentImagePicker {
37 
38     /**
39      * An interface for a listener that listens for when a document has been picked.
40      */
41     public interface SelectionListener {
42         /**
43          * Called when an document is selected from picker. At this point, the file hasn't been
44          * actually loaded and staged in the temp directory, so we are passing in a pending
45          * MessagePartData, which the consumer should use to display a placeholder image.
46          * @param pendingItem a temporary attachment data for showing the placeholder state.
47          */
onDocumentSelected(PendingAttachmentData pendingItem)48         void onDocumentSelected(PendingAttachmentData pendingItem);
49     }
50 
51     // The owning fragment.
52     private final Fragment mFragment;
53 
54     // The listener on the picker events.
55     private final SelectionListener mListener;
56 
57     private static final String EXTRA_PHOTO_URL = "photo_url";
58 
59     /**
60      * Creates a new instance of DocumentImagePicker.
61      * @param activity The activity that owns the picker, or the activity that hosts the owning
62      *        fragment.
63      */
DocumentImagePicker(final Fragment fragment, final SelectionListener listener)64     public DocumentImagePicker(final Fragment fragment,
65             final SelectionListener listener) {
66         mFragment = fragment;
67         mListener = listener;
68     }
69 
70     /**
71      * Intent out to open an image/video from document picker.
72      */
launchPicker()73     public void launchPicker() {
74         UIIntents.get().launchDocumentImagePicker(mFragment);
75     }
76 
77     /**
78      * Must be called from the fragment/activity's onActivityResult().
79      */
onActivityResult(final int requestCode, final int resultCode, final Intent data)80     public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
81         // Sometimes called after media item has been picked from the document picker.
82         String url = data.getStringExtra(EXTRA_PHOTO_URL);
83         if (url == null) {
84             // we're using the builtin photo picker which supplies the return
85             // url as it's "data"
86             url = data.getDataString();
87             if (url == null) {
88                 final Bundle extras = data.getExtras();
89                 if (extras != null) {
90                     final Uri uri = (Uri) extras.getParcelable(Intent.EXTRA_STREAM);
91                     if (uri != null) {
92                         url = uri.toString();
93                     }
94                 }
95             }
96         }
97 
98         // Guard against null uri cases for when the activity returns a null/invalid intent.
99         if (url != null) {
100             final Uri uri = Uri.parse(url);
101             prepareDocumentForAttachment(uri);
102         }
103     }
104 
prepareDocumentForAttachment(final Uri documentUri)105     private void prepareDocumentForAttachment(final Uri documentUri) {
106         // Notify our listener with a PendingAttachmentData containing the metadata.
107         // Asynchronously get the content type for the picked image since
108         // ImageUtils.getContentType() potentially involves I/O and can be expensive.
109         new SafeAsyncTask<Void, Void, String>() {
110             @Override
111             protected String doInBackgroundTimed(final Void... params) {
112                 if (FileUtil.isInPrivateDir(documentUri)) {
113                     // hacker sending private app data. Bail out
114                     if (LogUtil.isLoggable(LogUtil.BUGLE_TAG, LogUtil.ERROR)) {
115                         LogUtil.e(LogUtil.BUGLE_TAG, "Aborting attach of private app data ("
116                                 + documentUri + ")");
117                     }
118                     return null;
119                 }
120                 return ImageUtils.getContentType(
121                         Factory.get().getApplicationContext().getContentResolver(), documentUri);
122             }
123 
124             @Override
125             protected void onPostExecute(final String contentType) {
126                 if (contentType == null) {
127                     return;     // bad uri on input
128                 }
129                 // Ask the listener to create a temporary placeholder item to show the progress.
130                 final PendingAttachmentData pendingItem =
131                         PendingAttachmentData.createPendingAttachmentData(contentType,
132                                 documentUri);
133                 mListener.onDocumentSelected(pendingItem);
134             }
135         }.executeOnThreadPool();
136     }
137 }
138