View Single Post
Old 02-03-2011, 06:03 AM   #4
jsstylos
Junior Member
jsstylos has much to be proud ofjsstylos has much to be proud ofjsstylos has much to be proud ofjsstylos has much to be proud ofjsstylos has much to be proud ofjsstylos has much to be proud ofjsstylos has much to be proud ofjsstylos has much to be proud ofjsstylos has much to be proud ofjsstylos has much to be proud ofjsstylos has much to be proud of
 
Posts: 3
Karma: 27344
Join Date: Feb 2011
Device: Kindle 3
Hi there. I'm trying to get started with Kindle programming and your post intrigued me enough to look into the internal API issue.

I originally thought that the NoClassDefFoundError problem was a result of an obfuscation trick -- the KindleImplementation-1.1.jar contains a package called com.amazon.kindle.kindlet.internal.e, which seems to prevent the compiler from referencing the class of the same name. But I also ran into the same NoClassDefFoundError issue when trying to reference the interfaces in the com.amazon.kindle.kindlet.media package for the purpose of doing instanceof checks and casts. This confuses me much more than the problem referencing the internal e class. I'd love if someone could help shed light on this.

One can, however, access the internal.e class and the kindlet.media interfaces even without being able to directly reference them, though it requires elevated permissions to perform reflection, and is rather laborious to program.

Here is some code I wrote that plays a test.mp3 in the /mnt/us/developer/YourAppName/work/test.mp3 directory.

Code:
    private void playAudio () {
        Class contextClass = context.getClass();
        Method[] methods = contextClass.getDeclaredMethods();
        Method audioMethod = methods[1];
        
        Object audioManagerObject;
        Class audioManagerClass;
        
        try {
        	audioManagerObject = audioMethod.invoke(context, new Object[0]);
        	audioManagerClass = audioManagerObject.getClass();
        	
        	Method[] audioManagerMethods = audioManagerClass.getDeclaredMethods();
        	Method createAudioPlayerMethod = audioManagerMethods[10];
        	Class mediaSourceClass = createAudioPlayerMethod.getParameterTypes()[0];
        	Constructor[] mediaSourceConstructors = mediaSourceClass.getConstructors();
        	Constructor mediaSourceInputStreamConstructor = mediaSourceConstructors[3];
        	//Constructor mediaSourceUrlConstructor = mediaSourceConstructors[1]; // Use this to play from a url
        	
        	Object[] mediaSourceArgs = new Object[1];
        	mediaSourceArgs[0] = new FileInputStream(context.getHomeDirectory().getAbsolutePath() + "/" + "test.mp3");
        	Object mediaSourceObject = mediaSourceInputStreamConstructor.newInstance(mediaSourceArgs);
        	
        	Object[] createAudioPlayerArgs = new Object[1];
        	createAudioPlayerArgs[0] = mediaSourceObject;
        	Object audioObject = createAudioPlayerMethod.invoke(audioManagerObject, createAudioPlayerArgs);
        	Class audioClass = audioObject.getClass();
        	
        	Method[] audioMethods = audioClass.getDeclaredMethods();
        	        	
        	Method playMethod = audioMethods[12];
        	playMethod.invoke(audioObject, new Object[0]);
        	
		} catch (IllegalArgumentException e1) {
			e1.printStackTrace();
		} catch (IllegalAccessException e1) {
			e1.printStackTrace();
		} catch (InvocationTargetException e1) {
			e1.printStackTrace();
		} catch (FileNotFoundException e1) {
			e1.printStackTrace();
		} catch (InstantiationException e1) {
			e1.printStackTrace();
		}	
    }
The code uses reflection (which will throw an exception if you don't use the java.security.AllPermission trick, or perhaps some lesser permission that will just allow reflection) to list the classes and methods at runtime. The code currently uses hardcoded indices to pull out the appropriate methods and classes (these indices were determined by displaying the method names and parameter arguments for each of the methods in the list; instead of using hardcoded indices I should probably write a helper method to lookup the right method or class based on name and argument types, if there's not already a better helper in the reflection API).

This is clearly very messy code to write -- especially if you're mucking about with listeners and the like -- so I would really like to just be able to reference the classes and interfaces in the com.amazon.kindle.kindlet.media package at least directly. If someone can figure out how to do that, that would be very handy.
jsstylos is offline   Reply With Quote