1 /* 2 * Copyright (C) 2013 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.android.camera.app; 18 19 import android.content.Context; 20 import android.graphics.BitmapFactory; 21 import android.location.Location; 22 import android.net.Uri; 23 24 import com.android.camera.ImageTaskManager; 25 import com.android.camera.Storage; 26 import com.android.camera.exif.ExifInterface; 27 import com.android.camera.util.CameraUtil; 28 29 import java.lang.ref.WeakReference; 30 import java.util.ArrayList; 31 import java.util.Iterator; 32 33 public class PlaceholderManager implements ImageTaskManager { 34 private static final String TAG = "PlaceholderManager"; 35 36 public static final String PLACEHOLDER_MIME_TYPE = "application/placeholder-image"; 37 private final Context mContext; 38 39 final private ArrayList<WeakReference<TaskListener>> mListenerRefs; 40 41 public static class Session { 42 String outputTitle; 43 Uri outputUri; 44 long time; 45 46 Session(String title, Uri uri, long timestamp) { 47 outputTitle = title; 48 outputUri = uri; 49 time = timestamp; 50 } 51 } 52 53 public PlaceholderManager(Context context) { 54 mContext = context; 55 mListenerRefs = new ArrayList<WeakReference<TaskListener>>(); 56 } 57 58 @Override 59 public void addTaskListener(TaskListener l) { 60 synchronized (mListenerRefs) { 61 if (findTaskListener(l) == -1) { 62 mListenerRefs.add(new WeakReference<TaskListener>(l)); 63 } 64 } 65 } 66 67 @Override 68 public void removeTaskListener(TaskListener l) { 69 synchronized (mListenerRefs) { 70 int i = findTaskListener(l); 71 if (i != -1) { 72 mListenerRefs.remove(i); 73 } 74 } 75 } 76 77 @Override 78 public int getTaskProgress(Uri uri) { 79 return 0; 80 } 81 82 private int findTaskListener(TaskListener listener) { 83 int index = -1; 84 for (int i = 0; i < mListenerRefs.size(); i++) { 85 TaskListener l = mListenerRefs.get(i).get(); 86 if (l != null && l == listener) { 87 index = i; 88 break; 89 } 90 } 91 return index; 92 } 93 94 private Iterable<TaskListener> getListeners() { 95 return new Iterable<TaskListener>() { 96 @Override 97 public Iterator<TaskListener> iterator() { 98 return new ListenerIterator(); 99 } 100 }; 101 } 102 103 private class ListenerIterator implements Iterator<TaskListener> { 104 private int mIndex = 0; 105 private TaskListener mNext = null; 106 107 @Override 108 public boolean hasNext() { 109 while (mNext == null && mIndex < mListenerRefs.size()) { 110 mNext = mListenerRefs.get(mIndex).get(); 111 if (mNext == null) { 112 mListenerRefs.remove(mIndex); 113 } 114 } 115 return mNext != null; 116 } 117 118 @Override 119 public TaskListener next() { 120 hasNext(); // Populates mNext 121 mIndex++; 122 TaskListener next = mNext; 123 mNext = null; 124 return next; 125 } 126 127 @Override 128 public void remove() { 129 throw new UnsupportedOperationException(); 130 } 131 } 132 133 public Session insertPlaceholder(String title, byte[] placeholder, long timestamp) { 134 if (title == null || placeholder == null) { 135 throw new IllegalArgumentException("Null argument passed to insertPlaceholder"); 136 } 137 138 // Decode bounds 139 BitmapFactory.Options options = new BitmapFactory.Options(); 140 options.inJustDecodeBounds = true; 141 BitmapFactory.decodeByteArray(placeholder, 0, placeholder.length, options); 142 int width = options.outWidth; 143 int height = options.outHeight; 144 145 if (width <= 0 || height <= 0) { 146 throw new IllegalArgumentException("Image had bad height/width"); 147 } 148 149 Uri uri = 150 Storage.addImage(mContext.getContentResolver(), title, timestamp, null, 0, null, 151 placeholder, width, height, PLACEHOLDER_MIME_TYPE); 152 153 if (uri == null) { 154 return null; 155 } 156 157 String filePath = uri.getPath(); 158 synchronized (mListenerRefs) { 159 for (TaskListener l : getListeners()) { 160 l.onTaskQueued(filePath, uri); 161 } 162 } 163 164 return new Session(title, uri, timestamp); 165 } 166 167 public void replacePlaceholder(Session session, Location location, int orientation, 168 ExifInterface exif, byte[] jpeg, int width, int height, String mimeType) { 169 170 Storage.updateImage(session.outputUri, mContext.getContentResolver(), session.outputTitle, 171 session.time, location, orientation, exif, jpeg, width, height, mimeType); 172 173 synchronized (mListenerRefs) { 174 for (TaskListener l : getListeners()) { 175 l.onTaskDone(session.outputUri.getPath(), session.outputUri); 176 } 177 } 178 CameraUtil.broadcastNewPicture(mContext, session.outputUri); 179 } 180 181 public void removePlaceholder(Session session) { 182 Storage.deleteImage(mContext.getContentResolver(), session.outputUri); 183 } 184 185 } 186