Skip to content

Most visited

Recently visited

navigation
StorageClient / src / com.example.android.storageclient /

StorageClientFragment.java

1
/*
2
* Copyright (C) 2012 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.example.android.storageclient;
18
 
19
import android.app.Activity;
20
import android.app.Dialog;
21
import android.content.Intent;
22
import android.database.Cursor;
23
import android.graphics.Bitmap;
24
import android.graphics.BitmapFactory;
25
import android.net.Uri;
26
import android.os.AsyncTask;
27
import android.os.Bundle;
28
import android.os.ParcelFileDescriptor;
29
import android.provider.OpenableColumns;
30
import android.support.v4.app.DialogFragment;
31
import android.support.v4.app.Fragment;
32
import android.support.v4.app.FragmentManager;
33
import android.view.MenuItem;
34
import android.view.Window;
35
import android.widget.ImageView;
36
 
37
import com.example.android.common.logger.Log;
38
 
39
import java.io.FileDescriptor;
40
import java.io.IOException;
41
 
42
public class StorageClientFragment extends Fragment {
43
 
44
    // A request code's purpose is to match the result of a "startActivityForResult" with
45
    // the type of the original request.  Choose any value.
46
    private static final int READ_REQUEST_CODE = 1337;
47
 
48
    public static final String TAG = "StorageClientFragment";
49
 
50
    @Override
51
    public void onCreate(Bundle savedInstanceState) {
52
        super.onCreate(savedInstanceState);
53
        setHasOptionsMenu(true);
54
    }
55
 
56
    @Override
57
    public boolean onOptionsItemSelected(MenuItem item) {
58
        if (item.getItemId() == R.id.sample_action) {
59
            performFileSearch();
60
        }
61
        return true;
62
    }
63
 
64
    /**
65
     * Fires an intent to spin up the "file chooser" UI and select an image.
66
     */
67
    public void performFileSearch() {
68
 
70
        // ACTION_OPEN_DOCUMENT is the intent to choose a file via the system's file browser.
71
        Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
72
 
73
        // Filter to only show results that can be "opened", such as a file (as opposed to a list
74
        // of contacts or timezones)
75
        intent.addCategory(Intent.CATEGORY_OPENABLE);
76
 
77
        // Filter to show only images, using the image MIME data type.
78
        // If one wanted to search for ogg vorbis files, the type would be "audio/ogg".
79
        // To search for all documents available via installed storage providers, it would be
80
        // "*/*".
81
        intent.setType("image/*");
82
 
83
        startActivityForResult(intent, READ_REQUEST_CODE);
85
    }
86
 
87
    @Override
88
    public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
89
        Log.i(TAG, "Received an \"Activity Result\"");
91
        // The ACTION_OPEN_DOCUMENT intent was sent with the request code READ_REQUEST_CODE.
92
        // If the request code seen here doesn't match, it's the response to some other intent,
93
        // and the below code shouldn't run at all.
94
 
95
        if (requestCode == READ_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
96
            // The document selected by the user won't be returned in the intent.
97
            // Instead, a URI to that document will be contained in the return intent
98
            // provided to this method as a parameter.  Pull that uri using "resultData.getData()"
99
            Uri uri = null;
100
            if (resultData != null) {
101
                uri = resultData.getData();
102
                Log.i(TAG, "Uri: " + uri.toString());
103
                showImage(uri);
104
            }
106
        }
107
    }
108
 
109
    /**
110
     * Given the URI of an image, shows it on the screen using a DialogFragment.
111
     *
112
     * @param uri the Uri of the image to display.
113
     */
114
    public void showImage(Uri uri) {
116
        if (uri != null) {
117
            // Since the URI is to an image, create and show a DialogFragment to display the
118
            // image to the user.
119
            FragmentManager fm = getActivity().getSupportFragmentManager();
120
            ImageDialogFragment imageDialog = new ImageDialogFragment();
121
            Bundle fragmentArguments = new Bundle();
122
            fragmentArguments.putParcelable("URI", uri);
123
            imageDialog.setArguments(fragmentArguments);
124
            imageDialog.show(fm, "image_dialog");
125
        }
127
    }
128
 
129
 
130
    /**
131
     * DialogFragment which displays an image, given a URI.
132
     */
133
    public static class ImageDialogFragment extends DialogFragment {
134
        private Dialog mDialog;
135
        private Uri mUri;
136
 
137
        @Override
138
        public void onCreate(Bundle savedInstanceState) {
139
            super.onCreate(savedInstanceState);
140
            mUri = getArguments().getParcelable("URI");
141
        }
142
 
143
        /** Create a Bitmap from the URI for that image and return it.
144
         *
145
         * @param uri the Uri for the image to return.
146
         */
147
        private Bitmap getBitmapFromUri(Uri uri) {
148
            ParcelFileDescriptor parcelFileDescriptor = null;
149
            try {
150
                parcelFileDescriptor =
151
                        getActivity().getContentResolver().openFileDescriptor(uri, "r");
152
                FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
153
                Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
154
                parcelFileDescriptor.close();
155
                return image;
156
            } catch (Exception e) {
157
                Log.e(TAG, "Failed to load image.", e);
158
                return null;
159
            } finally {
160
                try {
161
                    if (parcelFileDescriptor != null) {
162
                        parcelFileDescriptor.close();
163
                    }
164
                } catch (IOException e) {
165
                    e.printStackTrace();
166
                    Log.e(TAG, "Error closing ParcelFile Descriptor");
167
                }
168
            }
169
        }
170
 
171
        @Override
172
        public Dialog onCreateDialog(Bundle savedInstanceState) {
173
            mDialog = super.onCreateDialog(savedInstanceState);
174
            // To optimize for the "lightbox" style layout.  Since we're not actually displaying a
175
            // title, remove the bar along the top of the fragment where a dialog title would
176
            // normally go.
177
            mDialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
178
            final ImageView imageView = new ImageView(getActivity());
179
            mDialog.setContentView(imageView);
180
 
182
            // Loading the image is going to require some sort of I/O, which must occur off the UI
183
            // thread.  Changing the ImageView to display the image must occur ON the UI thread.
184
            // The easiest way to divide up this labor is with an AsyncTask.  The doInBackground
185
            // method will run in a separate thread, but onPostExecute will run in the main
186
            // UI thread.
187
            AsyncTask<Uri, Void, Bitmap> imageLoadAsyncTask = new AsyncTask<Uri, Void, Bitmap>() {
188
                @Override
189
                protected Bitmap doInBackground(Uri... uris) {
190
                    dumpImageMetaData(uris[0]);
191
                    return getBitmapFromUri(uris[0]);
192
                }
193
 
194
                @Override
195
                protected void onPostExecute(Bitmap bitmap) {
196
                    imageView.setImageBitmap(bitmap);
197
                }
198
            };
199
            imageLoadAsyncTask.execute(mUri);
201
 
202
            return mDialog;
203
        }
204
 
205
        @Override
206
        public void onStop() {
207
            super.onStop();
208
            if (getDialog() != null) {
209
                getDialog().dismiss();
210
            }
211
        }
212
 
213
        /**
214
         * Grabs metadata for a document specified by URI, logs it to the screen.
215
         *
216
         * @param uri The uri for the document whose metadata should be printed.
217
         */
218
        public void dumpImageMetaData(Uri uri) {
220
 
221
            // The query, since it only applies to a single document, will only return one row.
222
            // no need to filter, sort, or select fields, since we want all fields for one
223
            // document.
224
            Cursor cursor = getActivity().getContentResolver()
225
                    .query(uri, null, null, null, null, null);
226
 
227
            try {
228
                // moveToFirst() returns false if the cursor has 0 rows.  Very handy for
229
                // "if there's anything to look at, look at it" conditionals.
230
                if (cursor != null && cursor.moveToFirst()) {
231
 
232
                    // Note it's called "Display Name".  This is provider-specific, and
233
                    // might not necessarily be the file name.
234
                    String displayName = cursor.getString(
235
                            cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
236
                    Log.i(TAG, "Display Name: " + displayName);
237
 
238
                    int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
239
                    // If the size is unknown, the value stored is null.  But since an int can't be
240
                    // null in java, the behavior is implementation-specific, which is just a fancy
241
                    // term for "unpredictable".  So as a rule, check if it's null before assigning
242
                    // to an int.  This will happen often:  The storage API allows for remote
243
                    // files, whose size might not be locally known.
244
                    String size = null;
245
                    if (!cursor.isNull(sizeIndex)) {
246
                        // Technically the column stores an int, but cursor.getString will do the
247
                        // conversion automatically.
248
                        size = cursor.getString(sizeIndex);
249
                    } else {
250
                        size = "Unknown";
251
                    }
252
                    Log.i(TAG, "Size: " + size);
253
                }
254
            } finally {
255
                if (cursor != null) {
256
                    cursor.close();
257
                }
258
            }
260
        }
261
    }
262
}
This site uses cookies to store your preferences for site-specific language and display options.

Hooray!

This class requires API level or higher

This doc is hidden because your selected API level for the documentation is . You can change the documentation API level with the selector above the left navigation.

For more information about specifying the API level your app requires, read Supporting Different Platform Versions.

Take a one-minute survey?
Help us improve Android tools and documentation.