MediaSaverImpl.java revision 3973deba115d398a25f0b74c2aea2ff4079355a5
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;
236df2d96e6a3d1f20ef04d2a29c9bb15f3002ad15Doris Liuimport android.graphics.BitmapFactory;
24ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kongimport android.location.Location;
25ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kongimport android.net.Uri;
26ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kongimport android.os.AsyncTask;
27ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kongimport android.os.Binder;
28ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kongimport android.os.IBinder;
2983a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kongimport android.provider.MediaStore.Video;
30ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kongimport android.util.Log;
31ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
320d00a8907096b9970ac64f52abbd2bfc1ed751b6Angus Kongimport com.android.gallery3d.exif.ExifInterface;
330d00a8907096b9970ac64f52abbd2bfc1ed751b6Angus Kong
3483a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kongimport java.io.File;
3583a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong
3686d36313d88fe96354f2cdd4f378e5ff8397c458Angus Kong/*
3786d36313d88fe96354f2cdd4f378e5ff8397c458Angus Kong * Service for saving images in the background thread.
3886d36313d88fe96354f2cdd4f378e5ff8397c458Angus Kong */
39ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kongpublic class MediaSaveService extends Service {
403973deba115d398a25f0b74c2aea2ff4079355a5Doris Liu    public static final String VIDEO_BASE_URI = "content://media/external/video/media";
413973deba115d398a25f0b74c2aea2ff4079355a5Doris Liu
42c40c411683da5db1e393e2172a451c3f9c511811Angus Kong    // The memory limit for unsaved image is 20MB.
43c40c411683da5db1e393e2172a451c3f9c511811Angus Kong    private static final int SAVE_TASK_MEMORY_LIMIT = 20 * 1024 * 1024;
44c40c411683da5db1e393e2172a451c3f9c511811Angus Kong    private static final String TAG = "CAM_" + MediaSaveService.class.getSimpleName();
45ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
46ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    private final IBinder mBinder = new LocalBinder();
47ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    private Listener mListener;
48c40c411683da5db1e393e2172a451c3f9c511811Angus Kong    // Memory used by the total queued save request, in bytes.
49c40c411683da5db1e393e2172a451c3f9c511811Angus Kong    private long mMemoryUse;
50ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
51ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    interface Listener {
52d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        public void onQueueStatus(boolean full);
53ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    }
54ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
55ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    interface OnMediaSavedListener {
56ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        public void onMediaSaved(Uri uri);
57ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    }
58ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
59ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    class LocalBinder extends Binder {
60ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        public MediaSaveService getService() {
61ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong            return MediaSaveService.this;
62ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        }
63ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    }
64ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
65ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    @Override
66ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    public IBinder onBind(Intent intent) {
67ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        return mBinder;
68ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    }
69ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
70ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    @Override
71ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    public int onStartCommand(Intent intent, int flag, int startId) {
72ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        return START_STICKY;
73ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    }
74ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
75ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    @Override
76ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    public void onDestroy() {
77ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    }
78ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
79ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    @Override
80ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    public void onCreate() {
81c40c411683da5db1e393e2172a451c3f9c511811Angus Kong        mMemoryUse = 0;
82ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    }
83ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
84ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    public boolean isQueueFull() {
85c40c411683da5db1e393e2172a451c3f9c511811Angus Kong        return (mMemoryUse >= SAVE_TASK_MEMORY_LIMIT);
86ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    }
87ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
88ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    public void addImage(final byte[] data, String title, long date, Location loc,
890d00a8907096b9970ac64f52abbd2bfc1ed751b6Angus Kong            int width, int height, int orientation, ExifInterface exif,
90ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong            OnMediaSavedListener l, ContentResolver resolver) {
91ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        if (isQueueFull()) {
92ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong            Log.e(TAG, "Cannot add image when the queue is full");
93ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong            return;
94ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        }
9583a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        ImageSaveTask t = new ImageSaveTask(data, title, date,
9683a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                (loc == null) ? null : new Location(loc),
970d00a8907096b9970ac64f52abbd2bfc1ed751b6Angus Kong                width, height, orientation, exif, resolver, l);
98ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
99c40c411683da5db1e393e2172a451c3f9c511811Angus Kong        mMemoryUse += data.length;
100ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        if (isQueueFull()) {
101ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong            onQueueFull();
102ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        }
103ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        t.execute();
104ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    }
105ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
1066df2d96e6a3d1f20ef04d2a29c9bb15f3002ad15Doris Liu    public void addImage(final byte[] data, String title, long date, Location loc,
1076df2d96e6a3d1f20ef04d2a29c9bb15f3002ad15Doris Liu                         int orientation, ExifInterface exif,
1086df2d96e6a3d1f20ef04d2a29c9bb15f3002ad15Doris Liu                         OnMediaSavedListener l, ContentResolver resolver) {
1096df2d96e6a3d1f20ef04d2a29c9bb15f3002ad15Doris Liu        // When dimensions are unknown, pass 0 as width and height,
1106df2d96e6a3d1f20ef04d2a29c9bb15f3002ad15Doris Liu        // and decode image for width and height later in a background thread
1116df2d96e6a3d1f20ef04d2a29c9bb15f3002ad15Doris Liu        addImage(data, title, date, loc, 0, 0, orientation, exif, l, resolver);
1126df2d96e6a3d1f20ef04d2a29c9bb15f3002ad15Doris Liu    }
113c40c411683da5db1e393e2172a451c3f9c511811Angus Kong    public void addImage(final byte[] data, String title, Location loc,
114c40c411683da5db1e393e2172a451c3f9c511811Angus Kong            int width, int height, int orientation, ExifInterface exif,
115c40c411683da5db1e393e2172a451c3f9c511811Angus Kong            OnMediaSavedListener l, ContentResolver resolver) {
116c40c411683da5db1e393e2172a451c3f9c511811Angus Kong        addImage(data, title, System.currentTimeMillis(), loc, width, height,
117c40c411683da5db1e393e2172a451c3f9c511811Angus Kong                orientation, exif, l, resolver);
118c40c411683da5db1e393e2172a451c3f9c511811Angus Kong    }
119c40c411683da5db1e393e2172a451c3f9c511811Angus Kong
12083a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong    public void addVideo(String path, long duration, ContentValues values,
12183a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong            OnMediaSavedListener l, ContentResolver resolver) {
12283a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        // We don't set a queue limit for video saving because the file
12383a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        // is already in the storage. Only updating the database.
12483a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        new VideoSaveTask(path, duration, values, l, resolver).execute();
12583a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong    }
12683a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong
127ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    public void setListener(Listener l) {
128ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        mListener = l;
129ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        if (l == null) return;
130d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        l.onQueueStatus(isQueueFull());
131ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    }
132ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
133ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    private void onQueueFull() {
134d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        if (mListener != null) mListener.onQueueStatus(true);
135ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    }
136ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
137ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    private void onQueueAvailable() {
138d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        if (mListener != null) mListener.onQueueStatus(false);
139ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    }
140ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
14183a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong    private class ImageSaveTask extends AsyncTask <Void, Void, Uri> {
142ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        private byte[] data;
143ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        private String title;
144ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        private long date;
145ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        private Location loc;
146ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        private int width, height;
147ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        private int orientation;
1480d00a8907096b9970ac64f52abbd2bfc1ed751b6Angus Kong        private ExifInterface exif;
149ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        private ContentResolver resolver;
150ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        private OnMediaSavedListener listener;
151ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
15283a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        public ImageSaveTask(byte[] data, String title, long date, Location loc,
15383a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                             int width, int height, int orientation, ExifInterface exif,
15483a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                             ContentResolver resolver, OnMediaSavedListener listener) {
155ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong            this.data = data;
156ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong            this.title = title;
157ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong            this.date = date;
158ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong            this.loc = loc;
159ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong            this.width = width;
160ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong            this.height = height;
161ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong            this.orientation = orientation;
1620d00a8907096b9970ac64f52abbd2bfc1ed751b6Angus Kong            this.exif = exif;
163ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong            this.resolver = resolver;
164ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong            this.listener = listener;
165ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        }
166ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
167ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        @Override
168ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        protected void onPreExecute() {
169ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong            // do nothing.
170ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        }
171ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
172ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        @Override
173ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        protected Uri doInBackground(Void... v) {
1746df2d96e6a3d1f20ef04d2a29c9bb15f3002ad15Doris Liu            if (width == 0 || height == 0) {
1756df2d96e6a3d1f20ef04d2a29c9bb15f3002ad15Doris Liu                // Decode bounds
1766df2d96e6a3d1f20ef04d2a29c9bb15f3002ad15Doris Liu                BitmapFactory.Options options = new BitmapFactory.Options();
1776df2d96e6a3d1f20ef04d2a29c9bb15f3002ad15Doris Liu                options.inJustDecodeBounds = true;
1786df2d96e6a3d1f20ef04d2a29c9bb15f3002ad15Doris Liu                BitmapFactory.decodeByteArray(data, 0, data.length, options);
1796df2d96e6a3d1f20ef04d2a29c9bb15f3002ad15Doris Liu                width = options.outWidth;
1806df2d96e6a3d1f20ef04d2a29c9bb15f3002ad15Doris Liu                height = options.outHeight;
1816df2d96e6a3d1f20ef04d2a29c9bb15f3002ad15Doris Liu            }
182ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong            return Storage.addImage(
1830d00a8907096b9970ac64f52abbd2bfc1ed751b6Angus Kong                    resolver, title, date, loc, orientation, exif, data, width, height);
184ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        }
185ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong
186ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        @Override
187ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        protected void onPostExecute(Uri uri) {
18883a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong            if (listener != null) listener.onMediaSaved(uri);
189c40c411683da5db1e393e2172a451c3f9c511811Angus Kong            boolean previouslyFull = isQueueFull();
190c40c411683da5db1e393e2172a451c3f9c511811Angus Kong            mMemoryUse -= data.length;
191c40c411683da5db1e393e2172a451c3f9c511811Angus Kong            if (isQueueFull() != previouslyFull) onQueueAvailable();
192ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong        }
193ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong    }
19483a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong
19583a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong    private class VideoSaveTask extends AsyncTask <Void, Void, Uri> {
19683a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        private String path;
19783a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        private long duration;
19883a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        private ContentValues values;
19983a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        private OnMediaSavedListener listener;
20083a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        private ContentResolver resolver;
20183a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong
20283a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        public VideoSaveTask(String path, long duration, ContentValues values,
20383a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                OnMediaSavedListener l, ContentResolver r) {
20483a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong            this.path = path;
20583a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong            this.duration = duration;
20683a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong            this.values = new ContentValues(values);
20783a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong            this.listener = l;
20883a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong            this.resolver = r;
20983a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        }
21083a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong
21183a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        @Override
21283a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        protected Uri doInBackground(Void... v) {
21383a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong            values.put(Video.Media.SIZE, new File(path).length());
21483a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong            values.put(Video.Media.DURATION, duration);
21583a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong            Uri uri = null;
21683a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong            try {
2173973deba115d398a25f0b74c2aea2ff4079355a5Doris Liu                Uri videoTable = Uri.parse(VIDEO_BASE_URI);
21883a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                uri = resolver.insert(videoTable, values);
21983a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong
22083a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                // Rename the video file to the final name. This avoids other
22183a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                // apps reading incomplete data.  We need to do it after we are
22283a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                // certain that the previous insert to MediaProvider is completed.
22383a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                String finalName = values.getAsString(
22483a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                        Video.Media.DATA);
22583a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                if (new File(path).renameTo(new File(finalName))) {
22683a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                    path = finalName;
22783a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                }
22883a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong
22983a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                resolver.update(uri, values, null, null);
23083a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong            } catch (Exception e) {
23183a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                // We failed to insert into the database. This can happen if
23283a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                // the SD card is unmounted.
23383a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                Log.e(TAG, "failed to add video to media store", e);
23483a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                uri = null;
23583a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong            } finally {
23683a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong                Log.v(TAG, "Current video URI: " + uri);
23783a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong            }
23883a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong            return uri;
23983a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        }
24083a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong
24183a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        @Override
24283a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        protected void onPostExecute(Uri uri) {
24383a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong            if (listener != null) listener.onMediaSaved(uri);
24483a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong        }
24583a99ae51a11af28553dfb77ef0ec91148671c9bAngus Kong    }
246ce5480e099fda944b9e96e4b750300944c3f4a4fAngus Kong}
247