MediaSaveService.java revision c40c411683da5db1e393e2172a451c3f9c511811
1ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong/*
2ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong * Copyright (C) 2013 The Android Open Source Project
3ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong *
4ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong * Licensed under the Apache License, Version 2.0 (the "License");
5ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong * you may not use this file except in compliance with the License.
6ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong * You may obtain a copy of the License at
7ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong *
8ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong *      http://www.apache.org/licenses/LICENSE-2.0
9ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong *
10ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong * Unless required by applicable law or agreed to in writing, software
11ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong * distributed under the License is distributed on an "AS IS" BASIS,
12ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong * See the License for the specific language governing permissions and
14ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong * limitations under the License.
15ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong */
16ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
17ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kongpackage com.android.camera;
18ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
19ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kongimport android.app.Service;
20ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kongimport android.content.ContentResolver;
2183a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kongimport android.content.ContentValues;
22ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kongimport android.content.Intent;
23ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kongimport android.location.Location;
24ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kongimport android.net.Uri;
25ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kongimport android.os.AsyncTask;
26ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kongimport android.os.Binder;
27ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kongimport android.os.IBinder;
2883a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kongimport android.provider.MediaStore.Video;
29ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kongimport android.util.Log;
30ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
310d00a8907096b9970ac64f52abbd2bfc1ed751b6Angus Kongimport com.android.gallery3d.exif.ExifInterface;
320d00a8907096b9970ac64f52abbd2bfc1ed751b6Angus Kong
3383a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kongimport java.io.File;
3483a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong
3586d36313d88fe96354f2cdd4f378e5ff8397c458Angus Kong/*
3686d36313d88fe96354f2cdd4f378e5ff8397c458Angus Kong * Service for saving images in the background thread.
3786d36313d88fe96354f2cdd4f378e5ff8397c458Angus Kong */
38ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kongpublic class MediaSaveService extends Service {
39c40c411683da5db1e393e2172a451c3f9c511811Angus Kong    // The memory limit for unsaved image is 20MB.
40c40c411683da5db1e393e2172a451c3f9c511811Angus Kong    private static final int SAVE_TASK_MEMORY_LIMIT = 20 * 1024 * 1024;
41c40c411683da5db1e393e2172a451c3f9c511811Angus Kong    private static final String TAG = "CAM_" + MediaSaveService.class.getSimpleName();
42ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
43ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    private final IBinder mBinder = new LocalBinder();
44ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    private Listener mListener;
45c40c411683da5db1e393e2172a451c3f9c511811Angus Kong    // Memory used by the total queued save request, in bytes.
46c40c411683da5db1e393e2172a451c3f9c511811Angus Kong    private long mMemoryUse;
47ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
48ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    interface Listener {
49d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        public void onQueueStatus(boolean full);
50ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    }
51ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
52ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    interface OnMediaSavedListener {
53ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        public void onMediaSaved(Uri uri);
54ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    }
55ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
56ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    class LocalBinder extends Binder {
57ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        public MediaSaveService getService() {
58ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong            return MediaSaveService.this;
59ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        }
60ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    }
61ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
62ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    @Override
63ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    public IBinder onBind(Intent intent) {
64ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        return mBinder;
65ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    }
66ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
67ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    @Override
68ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    public int onStartCommand(Intent intent, int flag, int startId) {
69ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        return START_STICKY;
70ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    }
71ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
72ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    @Override
73ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    public void onDestroy() {
74ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    }
75ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
76ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    @Override
77ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    public void onCreate() {
78c40c411683da5db1e393e2172a451c3f9c511811Angus Kong        mMemoryUse = 0;
79ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    }
80ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
81ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    public boolean isQueueFull() {
82c40c411683da5db1e393e2172a451c3f9c511811Angus Kong        return (mMemoryUse >= SAVE_TASK_MEMORY_LIMIT);
83ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    }
84ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
85ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    public void addImage(final byte[] data, String title, long date, Location loc,
860d00a8907096b9970ac64f52abbd2bfc1ed751b6Angus Kong            int width, int height, int orientation, ExifInterface exif,
87ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong            OnMediaSavedListener l, ContentResolver resolver) {
88ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        if (isQueueFull()) {
89ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong            Log.e(TAG, "Cannot add image when the queue is full");
90ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong            return;
91ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        }
9283a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        ImageSaveTask t = new ImageSaveTask(data, title, date,
9383a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                (loc == null) ? null : new Location(loc),
940d00a8907096b9970ac64f52abbd2bfc1ed751b6Angus Kong                width, height, orientation, exif, resolver, l);
95ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
96c40c411683da5db1e393e2172a451c3f9c511811Angus Kong        mMemoryUse += data.length;
97ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        if (isQueueFull()) {
98ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong            onQueueFull();
99ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        }
100ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        t.execute();
101ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    }
102ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
103c40c411683da5db1e393e2172a451c3f9c511811Angus Kong    public void addImage(final byte[] data, String title, Location loc,
104c40c411683da5db1e393e2172a451c3f9c511811Angus Kong            int width, int height, int orientation, ExifInterface exif,
105c40c411683da5db1e393e2172a451c3f9c511811Angus Kong            OnMediaSavedListener l, ContentResolver resolver) {
106c40c411683da5db1e393e2172a451c3f9c511811Angus Kong        addImage(data, title, System.currentTimeMillis(), loc, width, height,
107c40c411683da5db1e393e2172a451c3f9c511811Angus Kong                orientation, exif, l, resolver);
108c40c411683da5db1e393e2172a451c3f9c511811Angus Kong    }
109c40c411683da5db1e393e2172a451c3f9c511811Angus Kong
11083a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong    public void addVideo(String path, long duration, ContentValues values,
11183a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong            OnMediaSavedListener l, ContentResolver resolver) {
11283a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        // We don't set a queue limit for video saving because the file
11383a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        // is already in the storage. Only updating the database.
11483a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        new VideoSaveTask(path, duration, values, l, resolver).execute();
11583a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong    }
11683a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong
117ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    public void setListener(Listener l) {
118ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        mListener = l;
119ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        if (l == null) return;
120d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        l.onQueueStatus(isQueueFull());
121ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    }
122ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
123ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    private void onQueueFull() {
124d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        if (mListener != null) mListener.onQueueStatus(true);
125ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    }
126ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
127ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    private void onQueueAvailable() {
128d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        if (mListener != null) mListener.onQueueStatus(false);
129ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    }
130ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
13183a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong    private class ImageSaveTask extends AsyncTask <Void, Void, Uri> {
132ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        private byte[] data;
133ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        private String title;
134ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        private long date;
135ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        private Location loc;
136ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        private int width, height;
137ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        private int orientation;
1380d00a8907096b9970ac64f52abbd2bfc1ed751b6Angus Kong        private ExifInterface exif;
139ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        private ContentResolver resolver;
140ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        private OnMediaSavedListener listener;
141ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
14283a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        public ImageSaveTask(byte[] data, String title, long date, Location loc,
14383a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                             int width, int height, int orientation, ExifInterface exif,
14483a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                             ContentResolver resolver, OnMediaSavedListener listener) {
145ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong            this.data = data;
146ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong            this.title = title;
147ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong            this.date = date;
148ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong            this.loc = loc;
149ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong            this.width = width;
150ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong            this.height = height;
151ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong            this.orientation = orientation;
1520d00a8907096b9970ac64f52abbd2bfc1ed751b6Angus Kong            this.exif = exif;
153ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong            this.resolver = resolver;
154ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong            this.listener = listener;
155ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        }
156ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
157ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        @Override
158ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        protected void onPreExecute() {
159ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong            // do nothing.
160ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        }
161ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
162ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        @Override
163ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        protected Uri doInBackground(Void... v) {
164ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong            return Storage.addImage(
1650d00a8907096b9970ac64f52abbd2bfc1ed751b6Angus Kong                    resolver, title, date, loc, orientation, exif, data, width, height);
166ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        }
167ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
168ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        @Override
169ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        protected void onPostExecute(Uri uri) {
17083a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong            if (listener != null) listener.onMediaSaved(uri);
171c40c411683da5db1e393e2172a451c3f9c511811Angus Kong            boolean previouslyFull = isQueueFull();
172c40c411683da5db1e393e2172a451c3f9c511811Angus Kong            mMemoryUse -= data.length;
173c40c411683da5db1e393e2172a451c3f9c511811Angus Kong            if (isQueueFull() != previouslyFull) onQueueAvailable();
174ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        }
175ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    }
17683a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong
17783a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong    private class VideoSaveTask extends AsyncTask <Void, Void, Uri> {
17883a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        private String path;
17983a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        private long duration;
18083a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        private ContentValues values;
18183a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        private OnMediaSavedListener listener;
18283a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        private ContentResolver resolver;
18383a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong
18483a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        public VideoSaveTask(String path, long duration, ContentValues values,
18583a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                OnMediaSavedListener l, ContentResolver r) {
18683a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong            this.path = path;
18783a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong            this.duration = duration;
18883a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong            this.values = new ContentValues(values);
18983a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong            this.listener = l;
19083a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong            this.resolver = r;
19183a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        }
19283a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong
19383a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        @Override
19483a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        protected void onPreExecute() {
19583a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong            // do nothing.
19683a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        }
19783a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong
19883a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        @Override
19983a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        protected Uri doInBackground(Void... v) {
20083a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong            values.put(Video.Media.SIZE, new File(path).length());
20183a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong            values.put(Video.Media.DURATION, duration);
20283a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong            Uri uri = null;
20383a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong            try {
20483a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                Uri videoTable = Uri.parse("content://media/external/video/media");
20583a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                uri = resolver.insert(videoTable, values);
20683a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong
20783a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                // Rename the video file to the final name. This avoids other
20883a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                // apps reading incomplete data.  We need to do it after we are
20983a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                // certain that the previous insert to MediaProvider is completed.
21083a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                String finalName = values.getAsString(
21183a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                        Video.Media.DATA);
21283a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                if (new File(path).renameTo(new File(finalName))) {
21383a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                    path = finalName;
21483a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                }
21583a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong
21683a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                resolver.update(uri, values, null, null);
21783a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong            } catch (Exception e) {
21883a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                // We failed to insert into the database. This can happen if
21983a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                // the SD card is unmounted.
22083a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                Log.e(TAG, "failed to add video to media store", e);
22183a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                uri = null;
22283a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong            } finally {
22383a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                Log.v(TAG, "Current video URI: " + uri);
22483a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong            }
22583a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong            return uri;
22683a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        }
22783a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong
22883a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        @Override
22983a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        protected void onPostExecute(Uri uri) {
23083a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong            if (listener != null) listener.onMediaSaved(uri);
23183a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        }
23283a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong    }
233ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong}
234