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