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   // #ifdef includeSmsFeature
229   public byte[] getByteFromImage(Image img){
230     int w = img.getWidth();
231     int h = img.getHeight();
232     int data_int[] new intw * h ];
233 //    img.getRGB( data_int, 0, w, 0, 0, w, h );
234     byte[] data_byte = new bytew * h * ];
235     for int i = 0; i < w * h; ++i )
236     {
237     int color = data_int];
238     int offset = i * 3;
239     data_byteoffset byte ) ( ( color & 0xff0000 >> 16 );
240     data_byteoffset +
241     byte ) ( ( color & 0xff00 >> );
242     data_byteoffset + byte ) ( ( color & 0xff ) );
243     }
244     return data_byte;
245   }
246   
247   
248   public void addImageData(String photoname, Image imgdata, String albumname)
249       throws InvalidImageDataException, PersistenceMechanismException {
250 
251     try {
252       imageRS = RecordStore
253           .openRecordStore(ALBUM_LABEL + albumname, true);
254       imageInfoRS = RecordStore.openRecordStore(INFO_LABEL + albumname,
255           true);
256       int rid; // new record ID for Image (bytes)
257       int rid2; // new record ID for ImageData (metadata)
258       
259       
260 
261       ImageUtil converter = new ImageUtil();
262 
263       // NOTE: For some Siemen's phone, all images have to be less than
264       // 16K
265       // May have to check for this, or try to convert to a lesser format
266       // for display on Siemen's phones (Could put this in an Aspect)
267 
268       // Add Tucan
269       byte[] data1 = getByteFromImage(imgdata);
270       rid = imageRS.addRecord(data1, 0, data1.length);
271       ImageData ii = new ImageData(rid, ImageAccessor.ALBUM_LABEL
272           + albumname, photoname);
273       rid2 = imageInfoRS.getNextRecordID();
274       ii.setRecordId(rid2);
275       data1 = converter.getBytesFromImageInfo(ii);
276       imageInfoRS.addRecord(data1, 0, data1.length);
277 
278       imageRS.closeRecordStore();
279 
280       imageInfoRS.closeRecordStore();
281     catch (RecordStoreException e) {
282       throw new PersistenceMechanismException();
283     }
284   }
285   //#endif  
286   
287   
288   // #ifdef includeCopyPhoto
289   /**
290    @param photoname
291    @param imageData
292    @param albumname
293    @throws InvalidImageDataException
294    @throws PersistenceMechanismException
295    */
296   public void addImageData(String photoname, ImageData imageData, String albumnamethrows InvalidImageDataException, PersistenceMechanismException {
297     try {
298       imageRS = RecordStore.openRecordStore(ALBUM_LABEL + albumname, true);
299       imageInfoRS = RecordStore.openRecordStore(INFO_LABEL + albumname, true);
300       int rid2; // new record ID for ImageData (metadata)
301       ImageUtil converter = new ImageUtil();
302       rid2 = imageInfoRS.getNextRecordID();
303       imageData.setRecordId(rid2);
304       byte[] data1 = converter.getBytesFromImageInfo(imageData);
305       imageInfoRS.addRecord(data1, 0, data1.length);
306     catch (RecordStoreException e) {
307       throw new PersistenceMechanismException();
308     }finally{
309       try {
310         imageRS.closeRecordStore();
311         imageInfoRS.closeRecordStore();
312       catch (RecordStoreNotOpenException e) {
313         // TODO Auto-generated catch block
314         e.printStackTrace();
315       catch (RecordStoreException e) {
316         // TODO Auto-generated catch block
317         e.printStackTrace();
318       }
319     }
320   }
321   // #endif
322 
323   /**
324    * This will populate the imageInfo hashtable with the ImageInfo object,
325    * referenced by label name and populate the imageTable hashtable with Image
326    * objects referenced by the RMS record Id
327    
328    @throws PersistenceMechanismException
329    */
330   public ImageData[] loadImageDataFromRMS(String recordName)
331       throws PersistenceMechanismException, InvalidImageDataException {
332 
333     Vector imagesVector = new Vector();
334 
335     try {
336 
337 // [EF] not used      String storeName = ImageAccessor.ALBUM_LABEL + recordName;
338       String infoStoreName = ImageAccessor.INFO_LABEL + recordName;
339 
340       RecordStore infoStore = RecordStore.openRecordStore(infoStoreName,
341           false);
342       RecordEnumeration isEnum = infoStore.enumerateRecords(null, null,
343           false);
344 
345       while (isEnum.hasNextElement()) {
346         // Get next record
347         int currentId = isEnum.nextRecordId();
348         byte[] data = infoStore.getRecord(currentId);
349 
350         // Convert the data from a byte array into our ImageData
351         // (metadata) object
352         ImageUtil converter = new ImageUtil();
353         ImageData iiObject = converter.getImageInfoFromBytes(data);
354 
355         // Add the info to the metadata hashtable
356         String label = iiObject.getImageLabel();
357         imagesVector.addElement(iiObject);
358         model.getImageInfoTable().put(label, iiObject);
359 
360       }
361 
362       infoStore.closeRecordStore();
363 
364     }catch (RecordStoreException rse) {
365       throw new PersistenceMechanismException(rse);
366     }
367 
368     // Re-copy the contents into a smaller array
369     ImageData[] labelArray = new ImageData[imagesVector.size()];
370     imagesVector.copyInto(labelArray);
371     return labelArray;
372   }
373 
374   /**
375    * Update the Image metadata associated with this named photo
376    @throws InvalidImageDataException 
377    @throws PersistenceMechanismException 
378    */
379   public boolean updateImageInfo(ImageData oldData, ImageData newDatathrows InvalidImageDataException, PersistenceMechanismException {
380 
381     boolean success = false;
382     RecordStore infoStore = null;
383     try {
384 
385       // Parse the Data store name to get the Info store name
386       String infoStoreName = oldData.getParentAlbumName();
387       infoStoreName = ImageAccessor.INFO_LABEL + infoStoreName.substring(ImageAccessor.ALBUM_LABEL.length());
388       infoStore = RecordStore.openRecordStore(infoStoreName, false);
389 
390       ImageUtil converter = new ImageUtil();
391       byte[] imageDataBytes = converter.getBytesFromImageInfo(newData);
392 
393       infoStore.setRecord(oldData.getRecordId(), imageDataBytes, 0, imageDataBytes.length);
394 
395     catch (RecordStoreException rse) {
396       throw new PersistenceMechanismException(rse);
397     }
398 
399     // Update the Hashtable 'cache'
400     setImageInfo(oldData.getImageLabel(), newData);
401 
402     try {
403       infoStore.closeRecordStore();
404     catch (RecordStoreNotOpenException e) {
405       //No problem if the RecordStore is not Open
406     catch (RecordStoreException e) {
407       throw new PersistenceMechanismException(e);
408     }
409 
410     return success;
411   }
412 
413   /**
414    * Retrieve the metadata associated with a specified image (by name)
415    @throws ImageNotFoundException 
416    @throws NullAlbumDataReference 
417    */
418   public ImageData getImageInfo(String imageNamethrows ImageNotFoundException, NullAlbumDataReference {
419 
420     if (model == null)
421       throw new NullAlbumDataReference("Null reference to the Album data");
422 
423     ImageData ii = (ImageDatamodel.getImageInfoTable().get(imageName);
424 
425     if (ii == null)
426       throw new ImageNotFoundException(imageName +" was NULL in ImageAccessor Hashtable.");
427       
428 
429     return ii;
430 
431   }
432 
433   /**
434    * Update the hashtable with new ImageInfo data
435    */
436   public void setImageInfo(String imageName, ImageData newData) {
437 
438     model.getImageInfoTable().put(newData.getImageLabel(), newData);
439 
440   }
441 
442   /**
443    * Fetch a single image from the Record Store This should be used for
444    * loading images on-demand (only when they are viewed or sent via SMS etc.)
445    * to reduce startup time by loading them all at once.
446    @throws PersistenceMechanismException 
447    */
448   public Image loadSingleImageFromRMS(String recordName, String imageName,
449       int recordIdthrows PersistenceMechanismException {
450 
451     Image img = null;
452     byte[] imageData = loadImageBytesFromRMS(recordName, imageName,
453         recordId);
454     img = Image.createImage(imageData, 0, imageData.length);
455     return img;
456   }
457 
458   /**
459    * Get the data for an Image as a byte array. This is useful for sending
460    * images via SMS or HTTP
461    @throws PersistenceMechanismException 
462    */
463   public byte[] loadImageBytesFromRMS(String recordName, String imageName,
464       int recordIdthrows PersistenceMechanismException {
465 
466     byte[] imageData = null;
467 
468     try {
469 
470       RecordStore albumStore = RecordStore.openRecordStore(recordName,
471           false);
472       imageData = albumStore.getRecord(recordId);
473       albumStore.closeRecordStore();
474 
475     catch (RecordStoreException rse) {
476       throw new PersistenceMechanismException(rse);
477     }
478 
479     return imageData;
480   }
481 
482   /**
483    * Delete a single (specified) image from the (specified) record store. This
484    * will permanently delete the image data and metadata from the device.
485    @throws PersistenceMechanismException 
486    @throws NullAlbumDataReference 
487    @throws ImageNotFoundException 
488    */
489   public boolean deleteSingleImageFromRMS(String storeName, String imageNamethrows PersistenceMechanismException, ImageNotFoundException, NullAlbumDataReference {
490 
491     boolean success = false;
492 
493     // Open the record stores containing the byte data and the meta data
494     // (info)
495     try {
496 
497       // Verify storeName is name without pre-fix
498       imageRS = RecordStore
499           .openRecordStore(ALBUM_LABEL + storeName, true);
500       imageInfoRS = RecordStore.openRecordStore(INFO_LABEL + storeName,
501           true);
502 
503       ImageData imageData = getImageInfo(imageName);
504       int rid = imageData.getForeignRecordId();
505 
506       imageRS.deleteRecord(rid);
507       imageInfoRS.deleteRecord(rid);
508 
509       imageRS.closeRecordStore();
510       imageInfoRS.closeRecordStore();
511 
512     catch (RecordStoreException rse) {
513       throw new PersistenceMechanismException(rse);
514     }
515 
516     // TODO: It's not clear from the API whether the record store needs to
517     // be closed or not...
518 
519     return success;
520   }
521 
522   /**
523    * Define a new photo album for mobile photo users. This creates a new
524    * record store to store photos for the album.
525    @throws PersistenceMechanismException 
526    @throws InvalidPhotoAlbumNameException 
527    */
528   public void createNewPhotoAlbum(String albumNamethrows PersistenceMechanismException, InvalidPhotoAlbumNameException {
529     
530     RecordStore newAlbumRS = null;
531     RecordStore newAlbumInfoRS = null;
532     if (albumName.equals("")){
533       throw new InvalidPhotoAlbumNameException();
534     }
535     String[] names  = getAlbumNames();
536     for (int i = 0; i < names.length; i++) {
537       if (names[i].equals(albumName))
538         throw new InvalidPhotoAlbumNameException();
539     }
540     
541     try {
542       newAlbumRS = RecordStore.openRecordStore(ALBUM_LABEL + albumName,
543           true);
544       newAlbumInfoRS = RecordStore.openRecordStore(
545           INFO_LABEL + albumName, true);
546       newAlbumRS.closeRecordStore();
547       newAlbumInfoRS.closeRecordStore();
548     catch (RecordStoreException rse) {
549       throw new PersistenceMechanismException(rse);
550     }
551 
552   }
553 
554   public void deletePhotoAlbum(String albumNamethrows PersistenceMechanismException {
555 
556     try {
557       RecordStore.deleteRecordStore(ALBUM_LABEL + albumName);
558       RecordStore.deleteRecordStore(INFO_LABEL + albumName);
559     catch (RecordStoreException rse) {
560       throw new PersistenceMechanismException(rse);
561     }
562 
563   }
564 
565   /**
566    * Get the list of photo album names currently loaded.
567    
568    @return Returns the albumNames.
569    */
570   public String[] getAlbumNames() {
571     return albumNames;
572   }
573 }