Classes sorted by package:

core.comms
BaseMessaging

core.threads
BaseThread

core.ui
MainUIMidlet

core.ui.controller
AbstractController
AlbumController
BaseController
ControllerInterface
PhotoController
PhotoListController
PhotoViewController
ScreenSingleton

core.ui.datamodel
AlbumData
ImageAccessor
ImageData

core.ui.screens
AddPhotoToAlbum
AlbumListScreen
NewLabelScreen
PhotoListScreen
PhotoViewScreen
SplashScreen

core.util
Constants
ImageUtil

sms
NetworkScreen
SmsMessaging
SmsReceiverController
SmsReceiverThread
SmsSenderController
SmsReceiverThread
  1 /*
  2  * Created on Sep 13, 2004
  3  *
  4  */
  5 package ubc.midp.mobilephoto.core.ui.datamodel;
  6 
  7 import java.util.Vector;
  8 
  9 import javax.microedition.lcdui.Image;
 10 import javax.microedition.rms.RecordEnumeration;
 11 import javax.microedition.rms.RecordStore;
 12 import javax.microedition.rms.RecordStoreException;
 13 import javax.microedition.rms.RecordStoreNotOpenException;
 14 
 15 import lancs.midp.mobilephoto.lib.exceptions.ImageNotFoundException;
 16 import lancs.midp.mobilephoto.lib.exceptions.ImagePathNotValidException;
 17 import lancs.midp.mobilephoto.lib.exceptions.InvalidImageDataException;
 18 import lancs.midp.mobilephoto.lib.exceptions.InvalidImageFormatException;
 19 import lancs.midp.mobilephoto.lib.exceptions.InvalidPhotoAlbumNameException;
 20 import lancs.midp.mobilephoto.lib.exceptions.NullAlbumDataReference;
 21 import lancs.midp.mobilephoto.lib.exceptions.PersistenceMechanismException;
 22 import ubc.midp.mobilephoto.core.util.ImageUtil;
 23 
 24 /**
 25  @author trevor
 26  
 27  * This is the main data access class. It handles all the connectivity with the
 28  * RMS record stores to fetch and save data associated with MobilePhoto TODO:
 29  * Refactor into stable interface for future updates. We may want to access data
 30  * from RMS, or eventually direct from the 'file system' on devices that support
 31  * the FileConnection optional API.
 32  
 33  */
 34 public class ImageAccessor {
 35 
 36   // Note: Our midlet only ever has access to Record Stores it created
 37   // For now, use naming convention to create record stores used by
 38   // MobilePhoto
 39   public static final String ALBUM_LABEL = "mpa-"// "mpa- all album names
 40                             // are prefixed with
 41                             // this label
 42   public static final String INFO_LABEL = "mpi-"// "mpi- all album info
 43                           // stores are prefixed with
 44                           // this label
 45   public static final String DEFAULT_ALBUM_NAME = "My Photo Album"// default
 46                                     // album
 47                                     // name
 48 
 49   public static final String IMAGE_LABEL = "ImageList"// RecordStore name
 50                               // prefixed
 51 
 52   protected String[] albumNames; // User defined names of photo albums
 53 
 54   protected AlbumData model;
 55 
 56   // Record Stores
 57   private RecordStore imageRS = null;
 58   private RecordStore imageInfoRS = null;
 59 
 60   /*
 61    * Constructor
 62    */
 63   public ImageAccessor(AlbumData mod) {
 64     model = mod;
 65   }
 66 
 67   /**
 68    * Load all existing photo albums that are defined in the record store.
 69    
 70 
 71    @throws InvalidImageDataException
 72    @throws PersistenceMechanismException
 73    */
 74   public void loadAlbums() throws InvalidImageDataException,
 75       PersistenceMechanismException {
 76 
 77     // Try to find any existing Albums (record stores)
 78 
 79     String[] currentStores = RecordStore.listRecordStores();
 80 
 81     if (currentStores != null) {
 82       System.out.println("ImageAccessor::loadAlbums: Found: " + currentStores.length + " existing record stores");
 83       model.existingRecords = true;
 84       String[] temp = new String[currentStores.length];
 85       int count = 0;
 86 
 87       // Only use record stores that follow the naming convention defined
 88       for (int i = 0; i < currentStores.length; i++) {
 89         String curr = currentStores[i];
 90 
 91         // If this record store is a photo album...
 92         if (curr.startsWith(ALBUM_LABEL)) {
 93 
 94           // Strip out the mpa- identifier
 95           curr = curr.substring(4);
 96           // Add the album name to the array
 97           temp[i= curr;
 98           count++;
 99         }
100       }
101 
102       // Re-copy the contents into a smaller array now that we know the
103       // size
104       albumNames = new String[count];
105       int count2 = 0;
106       for (int i = 0; i < temp.length; i++) {
107         if (temp[i!= null) {
108           albumNames[count2= temp[i];
109           count2++;
110         }
111       }
112     else {
113       System.out.println("ImageAccessor::loadAlbums: 0 record stores exist. Creating default one.");
114       resetImageRecordStore();
115       loadAlbums();
116     }
117 //    System.out.println("ImageAccessor::loadAlbums: Finished ok! ");
118   }
119 
120   /**
121    * Reset the album data for MobilePhoto. This will delete all existing photo
122    * data from the record store and re-create the default album and photos.
123    
124    @throws InvalidImageFormatException
125    @throws ImagePathNotValidException
126    @throws InvalidImageDataException
127    @throws PersistenceMechanismException
128    
129    */
130   public void resetImageRecordStore() throws InvalidImageDataException, PersistenceMechanismException {
131 
132     String storeName = null;
133     String infoStoreName = null;
134 
135     // remove any existing album stores...
136     if (albumNames != null) {
137       for (int i = 0; i < albumNames.length; i++) {
138         try {
139           // Delete all existing stores containing Image objects as
140           // well as the associated ImageInfo objects
141           // Add the prefixes labels to the info store
142 
143           storeName = ALBUM_LABEL + albumNames[i];
144           infoStoreName = INFO_LABEL + albumNames[i];
145 
146           System.out.println("<* ImageAccessor.resetImageRecordStore() *> delete "+storeName);
147           
148           RecordStore.deleteRecordStore(storeName);
149           RecordStore.deleteRecordStore(infoStoreName);
150 
151         catch (RecordStoreException e) {
152           System.out.println("No record store named " + storeName
153               " to delete.");
154           System.out.println("...or...No record store named "
155               + infoStoreName + " to delete.");
156           System.out.println("Ignoring Exception: " + e);
157           // ignore any errors...
158         }
159       }
160     else {
161       // Do nothing for now
162       System.out
163           .println("ImageAccessor::resetImageRecordStore: albumNames array was null. Nothing to delete.");
164     }
165 
166     // Now, create a new default album for testing
167     addImageData("Tucan Sam""/images/Tucan.png",
168         ImageAccessor.DEFAULT_ALBUM_NAME);
169     // Add Penguin
170     addImageData("Linux Penguin""/images/Penguin.png",
171         ImageAccessor.DEFAULT_ALBUM_NAME);
172     // Add Duke
173     addImageData("Duke (Sun)""/images/Duke1.PNG",
174         ImageAccessor.DEFAULT_ALBUM_NAME);
175     addImageData("UBC Logo""/images/ubcLogo.PNG",
176         ImageAccessor.DEFAULT_ALBUM_NAME);
177     // Add Gail
178     addImageData("Gail""/images/Gail1.PNG",
179         ImageAccessor.DEFAULT_ALBUM_NAME);
180     // Add JG
181     addImageData("J. Gosling""/images/Gosling1.PNG",
182         ImageAccessor.DEFAULT_ALBUM_NAME);
183     // Add GK
184     addImageData("Gregor""/images/Gregor1.PNG",
185         ImageAccessor.DEFAULT_ALBUM_NAME);
186     // Add KDV
187     addImageData("Kris""/images/Kdvolder1.PNG",
188         ImageAccessor.DEFAULT_ALBUM_NAME);
189 
190   }
191 
192   public void addImageData(String photoname, String path, String albumname)
193       throws InvalidImageDataException, PersistenceMechanismException {
194 
195     try {
196       imageRS = RecordStore
197           .openRecordStore(ALBUM_LABEL + albumname, true);
198       imageInfoRS = RecordStore.openRecordStore(INFO_LABEL + albumname,
199           true);
200 
201       int rid; // new record ID for Image (bytes)
202       int rid2; // new record ID for ImageData (metadata)
203 
204       ImageUtil converter = new ImageUtil();
205 
206       // NOTE: For some Siemen's phone, all images have to be less than
207       // 16K
208       // May have to check for this, or try to convert to a lesser format
209       // for display on Siemen's phones (Could put this in an Aspect)
210 
211       // Add Tucan
212       byte[] data1 = converter.readImageAsByteArray(path);
213       rid = imageRS.addRecord(data1, 0, data1.length);
214       ImageData ii = new ImageData(rid, ImageAccessor.ALBUM_LABEL
215           + albumname, photoname);
216       rid2 = imageInfoRS.getNextRecordID();
217       ii.setRecordId(rid2);
218       data1 = converter.getBytesFromImageInfo(ii);
219       imageInfoRS.addRecord(data1, 0, data1.length);
220 
221       imageRS.closeRecordStore();
222 
223       imageInfoRS.closeRecordStore();
224     catch (RecordStoreException e) {
225       throw new PersistenceMechanismException();
226     }
227   }
228   public byte[] getByteFromImage(Image img){
229     int w = img.getWidth();
230     int h = img.getHeight();
231     int data_int[] new intw * h ];
232 //    img.getRGB( data_int, 0, w, 0, 0, w, h );
233     byte[] data_byte = new bytew * h * ];
234     for int i = 0; i < w * h; ++i )
235     {
236     int color = data_int];
237     int offset = i * 3;
238     data_byteoffset byte ) ( ( color & 0xff0000 >> 16 );
239     data_byteoffset +
240     byte ) ( ( color & 0xff00 >> );
241     data_byteoffset + byte ) ( ( color & 0xff ) );
242     }
243     return data_byte;
244   }
245   
246   
247   public void addImageData(String photoname, Image imgdata, String albumname)
248       throws InvalidImageDataException, PersistenceMechanismException {
249 
250     try {
251       imageRS = RecordStore
252           .openRecordStore(ALBUM_LABEL + albumname, true);
253       imageInfoRS = RecordStore.openRecordStore(INFO_LABEL + albumname,
254           true);
255       int rid; // new record ID for Image (bytes)
256       int rid2; // new record ID for ImageData (metadata)
257       
258       
259 
260       ImageUtil converter = new ImageUtil();
261 
262       // NOTE: For some Siemen's phone, all images have to be less than
263       // 16K
264       // May have to check for this, or try to convert to a lesser format
265       // for display on Siemen's phones (Could put this in an Aspect)
266 
267       // Add Tucan
268       byte[] data1 = getByteFromImage(imgdata);
269       rid = imageRS.addRecord(data1, 0, data1.length);
270       ImageData ii = new ImageData(rid, ImageAccessor.ALBUM_LABEL
271           + albumname, photoname);
272       rid2 = imageInfoRS.getNextRecordID();
273       ii.setRecordId(rid2);
274       data1 = converter.getBytesFromImageInfo(ii);
275       imageInfoRS.addRecord(data1, 0, data1.length);
276 
277       imageRS.closeRecordStore();
278 
279       imageInfoRS.closeRecordStore();
280     catch (RecordStoreException e) {
281       throw new PersistenceMechanismException();
282     }
283   }
284   
285   
286   /**
287    @param photoname
288    @param imageData
289    @param albumname
290    @throws InvalidImageDataException
291    @throws PersistenceMechanismException
292    */
293   public void addImageData(String photoname, ImageData imageData, String albumnamethrows InvalidImageDataException, PersistenceMechanismException {
294     try {
295       imageRS = RecordStore.openRecordStore(ALBUM_LABEL + albumname, true);
296       imageInfoRS = RecordStore.openRecordStore(INFO_LABEL + albumname, true);
297       int rid2; // new record ID for ImageData (metadata)
298       ImageUtil converter = new ImageUtil();
299       rid2 = imageInfoRS.getNextRecordID();
300       imageData.setRecordId(rid2);
301       byte[] data1 = converter.getBytesFromImageInfo(imageData);
302       imageInfoRS.addRecord(data1, 0, data1.length);
303     catch (RecordStoreException e) {
304       throw new PersistenceMechanismException();
305     }finally{
306       try {
307         imageRS.closeRecordStore();
308         imageInfoRS.closeRecordStore();
309       catch (RecordStoreNotOpenException e) {
310         // TODO Auto-generated catch block
311         e.printStackTrace();
312       catch (RecordStoreException e) {
313         // TODO Auto-generated catch block
314         e.printStackTrace();
315       }
316     }
317   }
318 
319   /**
320    * This will populate the imageInfo hashtable with the ImageInfo object,
321    * referenced by label name and populate the imageTable hashtable with Image
322    * objects referenced by the RMS record Id
323    
324    @throws PersistenceMechanismException
325    */
326   public ImageData[] loadImageDataFromRMS(String recordName)
327       throws PersistenceMechanismException, InvalidImageDataException {
328 
329     Vector imagesVector = new Vector();
330 
331     try {
332 
333 // [EF] not used      String storeName = ImageAccessor.ALBUM_LABEL + recordName;
334       String infoStoreName = ImageAccessor.INFO_LABEL + recordName;
335 
336       RecordStore infoStore = RecordStore.openRecordStore(infoStoreName,
337           false);
338       RecordEnumeration isEnum = infoStore.enumerateRecords(null, null,
339           false);
340 
341       while (isEnum.hasNextElement()) {
342         // Get next record
343         int currentId = isEnum.nextRecordId();
344         byte[] data = infoStore.getRecord(currentId);
345 
346         // Convert the data from a byte array into our ImageData
347         // (metadata) object
348         ImageUtil converter = new ImageUtil();
349         ImageData iiObject = converter.getImageInfoFromBytes(data);
350 
351         // Add the info to the metadata hashtable
352         String label = iiObject.getImageLabel();
353         imagesVector.addElement(iiObject);
354         model.getImageInfoTable().put(label, iiObject);
355 
356       }
357 
358       infoStore.closeRecordStore();
359 
360     }catch (RecordStoreException rse) {
361       throw new PersistenceMechanismException(rse);
362     }
363 
364     // Re-copy the contents into a smaller array
365     ImageData[] labelArray = new ImageData[imagesVector.size()];
366     imagesVector.copyInto(labelArray);
367     return labelArray;
368   }
369 
370   /**
371    * Update the Image metadata associated with this named photo
372    @throws InvalidImageDataException 
373    @throws PersistenceMechanismException 
374    */
375   public boolean updateImageInfo(ImageData oldData, ImageData newDatathrows InvalidImageDataException, PersistenceMechanismException {
376 
377     boolean success = false;
378     RecordStore infoStore = null;
379     try {
380 
381       // Parse the Data store name to get the Info store name
382       String infoStoreName = oldData.getParentAlbumName();
383       infoStoreName = ImageAccessor.INFO_LABEL + infoStoreName.substring(ImageAccessor.ALBUM_LABEL.length());
384       infoStore = RecordStore.openRecordStore(infoStoreName, false);
385 
386       ImageUtil converter = new ImageUtil();
387       byte[] imageDataBytes = converter.getBytesFromImageInfo(newData);
388 
389       infoStore.setRecord(oldData.getRecordId(), imageDataBytes, 0, imageDataBytes.length);
390 
391     catch (RecordStoreException rse) {
392       throw new PersistenceMechanismException(rse);
393     }
394 
395     // Update the Hashtable 'cache'
396     setImageInfo(oldData.getImageLabel(), newData);
397 
398     try {
399       infoStore.closeRecordStore();
400     catch (RecordStoreNotOpenException e) {
401       //No problem if the RecordStore is not Open
402     catch (RecordStoreException e) {
403       throw new PersistenceMechanismException(e);
404     }
405 
406     return success;
407   }
408 
409   /**
410    * Retrieve the metadata associated with a specified image (by name)
411    @throws ImageNotFoundException 
412    @throws NullAlbumDataReference 
413    */
414   public ImageData getImageInfo(String imageNamethrows ImageNotFoundException, NullAlbumDataReference {
415 
416     if (model == null)
417       throw new NullAlbumDataReference("Null reference to the Album data");
418 
419     ImageData ii = (ImageDatamodel.getImageInfoTable().get(imageName);
420 
421     if (ii == null)
422       throw new ImageNotFoundException(imageName +" was NULL in ImageAccessor Hashtable.");
423       
424 
425     return ii;
426 
427   }
428 
429   /**
430    * Update the hashtable with new ImageInfo data
431    */
432   public void setImageInfo(String imageName, ImageData newData) {
433 
434     model.getImageInfoTable().put(newData.getImageLabel(), newData);
435 
436   }
437 
438   /**
439    * Fetch a single image from the Record Store This should be used for
440    * loading images on-demand (only when they are viewed or sent via SMS etc.)
441    * to reduce startup time by loading them all at once.
442    @throws PersistenceMechanismException 
443    */
444   public Image loadSingleImageFromRMS(String recordName, String imageName,
445       int recordIdthrows PersistenceMechanismException {
446 
447     Image img = null;
448     byte[] imageData = loadImageBytesFromRMS(recordName, imageName,
449         recordId);
450     img = Image.createImage(imageData, 0, imageData.length);
451     return img;
452   }
453 
454   /**
455    * Get the data for an Image as a byte array. This is useful for sending
456    * images via SMS or HTTP
457    @throws PersistenceMechanismException 
458    */
459   public byte[] loadImageBytesFromRMS(String recordName, String imageName,
460       int recordIdthrows PersistenceMechanismException {
461 
462     byte[] imageData = null;
463 
464     try {
465 
466       RecordStore albumStore = RecordStore.openRecordStore(recordName,
467           false);
468       imageData = albumStore.getRecord(recordId);
469       albumStore.closeRecordStore();
470 
471     catch (RecordStoreException rse) {
472       throw new PersistenceMechanismException(rse);
473     }
474 
475     return imageData;
476   }
477 
478   /**
479    * Delete a single (specified) image from the (specified) record store. This
480    * will permanently delete the image data and metadata from the device.
481    @throws PersistenceMechanismException 
482    @throws NullAlbumDataReference 
483    @throws ImageNotFoundException 
484    */
485   public boolean deleteSingleImageFromRMS(String storeName, String imageNamethrows PersistenceMechanismException, ImageNotFoundException, NullAlbumDataReference {
486 
487     boolean success = false;
488 
489     // Open the record stores containing the byte data and the meta data
490     // (info)
491     try {
492 
493       // Verify storeName is name without pre-fix
494       imageRS = RecordStore
495           .openRecordStore(ALBUM_LABEL + storeName, true);
496       imageInfoRS = RecordStore.openRecordStore(INFO_LABEL + storeName,
497           true);
498 
499       ImageData imageData = getImageInfo(imageName);
500       int rid = imageData.getForeignRecordId();
501 
502       imageRS.deleteRecord(rid);
503       imageInfoRS.deleteRecord(rid);
504 
505       imageRS.closeRecordStore();
506       imageInfoRS.closeRecordStore();
507 
508     catch (RecordStoreException rse) {
509       throw new PersistenceMechanismException(rse);
510     }
511 
512     // TODO: It's not clear from the API whether the record store needs to
513     // be closed or not...
514 
515     return success;
516   }
517 
518   /**
519    * Define a new photo album for mobile photo users. This creates a new
520    * record store to store photos for the album.
521    @throws PersistenceMechanismException 
522    @throws InvalidPhotoAlbumNameException 
523    */
524   public void createNewPhotoAlbum(String albumNamethrows PersistenceMechanismException, InvalidPhotoAlbumNameException {
525     
526     RecordStore newAlbumRS = null;
527     RecordStore newAlbumInfoRS = null;
528     if (albumName.equals("")){
529       throw new InvalidPhotoAlbumNameException();
530     }
531     String[] names  = getAlbumNames();
532     for (int i = 0; i < names.length; i++) {
533       if (names[i].equals(albumName))
534         throw new InvalidPhotoAlbumNameException();
535     }
536     
537     try {
538       newAlbumRS = RecordStore.openRecordStore(ALBUM_LABEL + albumName,
539           true);
540       newAlbumInfoRS = RecordStore.openRecordStore(
541           INFO_LABEL + albumName, true);
542       newAlbumRS.closeRecordStore();
543       newAlbumInfoRS.closeRecordStore();
544     catch (RecordStoreException rse) {
545       throw new PersistenceMechanismException(rse);
546     }
547 
548   }
549 
550   public void deletePhotoAlbum(String albumNamethrows PersistenceMechanismException {
551 
552     try {
553       RecordStore.deleteRecordStore(ALBUM_LABEL + albumName);
554       RecordStore.deleteRecordStore(INFO_LABEL + albumName);
555     catch (RecordStoreException rse) {
556       throw new PersistenceMechanismException(rse);
557     }
558 
559   }
560 
561   /**
562    * Get the list of photo album names currently loaded.
563    
564    @return Returns the albumNames.
565    */
566   public String[] getAlbumNames() {
567     return albumNames;
568   }
569 }