I am trying to use a piece of code from a native java android app as a module in my project, but cannot seem to get it working.
First off I have to confess to being no java programmer, but have done a lot of googling and searching of the Q&A.
I am using Mobile SDK 1.8.2 for android, compiling with v8.
My module is building with no errors as the onAppCreate and startStreaming debug entries appear in the Emulator Process Log up until the startActivity call which produces the following error:
E/TiJSError( 935): (main) [5,3776] - Message: Uncaught Error: Unable to find explicit activity class {uk.co.perfecthomecomputers.streamer/uk.co.perfecthomecomputers.streamer.MainActivity}; have you declared this activity in your AndroidManifest.xml?This makes no sense to me as the activity is in the same package (uk.co.perfecthomecomputers.streamer) as the module code that is working fine.
Also I have included an entry for the activity in the modules timodule.xml file and that seems to be copied through to the apps androidmanifest.xml file in the build folder fine.
I have followed advice from other posts about building modules using 1.8.x and included all the relevant jars to get the module compiled so I don't think that is the issue.
Also I have inspected the jar file that the module produces and it appears to contain class names for all the additional code. I think it just my lack of understanding of Android activities and intents so hopefully I have just missed something that is obvious to someone less stupid than me!
The module code that is trying to call the activity is as follows:
package uk.co.perfecthomecomputers.streamer; import org.appcelerator.kroll.KrollModule; import org.appcelerator.kroll.annotations.Kroll; import org.appcelerator.titanium.TiApplication; import org.appcelerator.kroll.common.Log; import android.app.Activity; import android.content.Intent; @Kroll.module(name="Streamer", id="uk.co.perfecthomecomputers.streamer") public class StreamerModule extends KrollModule { // Standard Debugging variables private static final String LCAT = "StreamerModule"; public StreamerModule() { super(); } @Kroll.onAppCreate public static void onAppCreate(TiApplication app) { Log.d(LCAT, "inside onAppCreate"); // put module init code that needs to run when the application is created } @Kroll.method public void startStreaming() { Intent intent = new Intent(); intent.setClassName("uk.co.perfecthomecomputers.streamer", "uk.co.perfecthomecomputers.streamer.MainActivity"); Activity activity = TiApplication.getAppRootOrCurrentActivity(); Log.d(LCAT, "Got Here!"); activity.startActivity(intent); Log.d(LCAT, "But Not Here!"); } }
The timodule.xml entry is as follows:
<android xmlns:android="http://schemas.android.com/apk/res/android"> <manifest> <application> <activity android:name="uk.co.perfecthomecomputers.streamer.MainActivity" /> </application> </manifest> </android>And the AndroidManifest.xml file ends up containing:
<application android:icon="@drawable/appicon" android:label="AME Sound" android:name="AmeSoundApplication" android:debuggable="false"> <activity android:name="uk.co.perfecthomecomputers.streamer.MainActivity"/> <activity android:name=".AmeSoundActivity" android:label="AME Sound" android:theme="@style/Theme.Titanium" android:configChanges="keyboardHidden|orientation"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="org.appcelerator.titanium.TiActivity" android:configChanges="keyboardHidden|orientation" /> <activity android:name="org.appcelerator.titanium.TiTranslucentActivity" android:configChanges="keyboardHidden|orientation" android:theme="@android:style/Theme.Translucent" /> <activity android:name="org.appcelerator.titanium.TiModalActivity" android:configChanges="keyboardHidden|orientation" android:theme="@android:style/Theme.Translucent" /> <activity android:name="ti.modules.titanium.ui.TiTabActivity" android:configChanges="keyboardHidden|orientation" /> <activity android:name="ti.modules.titanium.ui.android.TiPreferencesActivity" /> <service android:name="org.appcelerator.titanium.analytics.TiAnalyticsService" android:exported="false" /> </application>I have declared the module in the tiapp.xml file and the module itself seems to load and run correctly as the onAppCreate debug entries are appearing in the log:
<modules> <module platform="android" version="1.0">uk.co.perfecthomecomputers.streamer</module> </modules>The Android Emulator Process log is as follows: Any help or advice very gratefully received.
Cheers
Des
3 Answers
OK, I have managed to sort this out, again, I qualify the answer with the caveat that I am not a java programmer so the code below is not very elegant in the way the result is passed back to the app. But it works!
My thoughts in the original question about declaring the activity in timodule.xml file were irrelevant, you do not need to do that.
The issue appears to be how the activity is declared in the module itself.
Below is an the code for a module that uses the Google speech recognition engine:
MODULE CODE:
package uk.co.phc.speech; import java.util.ArrayList; import java.util.HashMap; import org.appcelerator.kroll.KrollDict; import org.appcelerator.kroll.KrollFunction; import org.appcelerator.kroll.KrollInvocation; import org.appcelerator.kroll.KrollModule; import org.appcelerator.kroll.KrollProxy; import org.appcelerator.kroll.annotations.Kroll; import org.appcelerator.kroll.common.Log; import org.appcelerator.kroll.common.TiConfig; import org.appcelerator.titanium.ContextSpecific; import org.appcelerator.titanium.TiApplication; import org.appcelerator.titanium.TiC; import org.appcelerator.titanium.TiContext; import org.appcelerator.titanium.proxy.IntentProxy; import org.appcelerator.titanium.util.TiActivityResultHandler; import org.appcelerator.titanium.util.TiActivitySupport; import android.app.Activity; import android.content.Intent; import android.speech.RecognizerIntent; @Kroll.module(name="Speech", id="uk.co.phc.speech") @ContextSpecific public class SpeechModule extends KrollModule implements TiActivityResultHandler { private static final String WORD_0 = "word_0"; private static final String WORD_1 = "word_1"; private static final String WORD_2 = "word_2"; private static final String WORD_3 = "word_3"; private static final String WORD_4 = "word_4"; private static final String WORD_5 = "word_5"; private static final String WORD_6 = "word_6"; private static final String WORD_7 = "word_7"; private static final String WORD_8 = "word_8"; private static final String WORD_9 = "word_9"; private static final String NO_WORDS = "no_words"; private static final String LCAT = "SpeechModule"; private static final boolean DBG = TiConfig.LOGD; protected KrollFunction resultCallback; protected int requestCode; @Kroll.constant public static final int EVENT_SUCCESS = -1; @Kroll.constant public static final int EVENT_CANCELLED = 0; public SpeechModule() { super(); } public SpeechModule(TiContext tiContext) { this(); } @Kroll.onAppCreate public static void onAppCreate(TiApplication app) { Log.d(LCAT, "inside onAppCreate"); } @Kroll.method public void getSpeech(KrollFunction handler) { this.resultCallback = handler; Activity activity = TiApplication.getInstance().getCurrentActivity(); TiActivitySupport support = (TiActivitySupport) activity; requestCode = support.getUniqueResultCode(); Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); intent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, getClass().getPackage().getName()); intent.putExtra(RecognizerIntent.EXTRA_PROMPT, "WAITING INSTRUCTION"); intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 10); TiActivitySupport activitySupport = (TiActivitySupport) activity; activitySupport.launchActivityForResult(intent, requestCode, this); } @Override public void onResult(Activity activity, int thisRequestCode, int resultCode, Intent data) { if ( thisRequestCode == requestCode ) { ArrayList<String> suggestedWords = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); KrollDict event = new KrollDict(); int noWords = suggestedWords.size(); event.put(NO_WORDS, noWords); if (noWords > 0) { event.put(WORD_0, suggestedWords.get(0)); } if (noWords > 1) { event.put(WORD_1, suggestedWords.get(1)); } if (noWords > 2) { event.put(WORD_2, suggestedWords.get(2)); } if (noWords > 3) { event.put(WORD_3, suggestedWords.get(3)); } if (noWords > 4) { event.put(WORD_4, suggestedWords.get(4)); } if (noWords > 5) { event.put(WORD_5, suggestedWords.get(5)); } if (noWords > 6) { event.put(WORD_6, suggestedWords.get(6)); } if (noWords > 7) { event.put(WORD_7, suggestedWords.get(7)); } if (noWords > 8) { event.put(WORD_8, suggestedWords.get(8)); } if (noWords > 9) { event.put(WORD_9, suggestedWords.get(9)); } resultCallback.callAsync(getKrollObject(), new Object[]{ event }); } } @Override public void onError(Activity activity, int requestCode, Exception e) { Log.i(LCAT, "ONERROR CALLED"); if (resultCallback == null) return; KrollDict event = new KrollDict(); event.put(TiC.EVENT_PROPERTY_REQUEST_CODE, requestCode); event.put(TiC.EVENT_PROPERTY_ERROR, e.getMessage()); event.put(TiC.EVENT_PROPERTY_SOURCE, this); resultCallback.callAsync(getKrollObject(), new Object[]{ event }); } private void fireSuccess(String wordlist) { HashMap<String, Object> evt = new HashMap<String, Object>(); evt.put("success", wordlist); fireEvent("success", evt); } }JAVASCRIPT TO CALL MODULE
function recognise() { stt.getSpeech(function(e) { var recognised = 0; var noWords = e.no_words; var heard = '*'; if (noWords >= 0) { heard += e.word_0 + '*'; } if (noWords >= 1) { heard += e.word_1 + '*'; } if (noWords >= 2) { heard += e.word_2 + '*'; } if (noWords >= 3) { heard += e.word_3 + '*'; } if (noWords >= 4) { heard += e.word_4 + '*'; } if (noWords >= 5) { heard += e.word_5 + '*'; } if (noWords >= 6) { heard += e.word_6 + '*'; } if (noWords >= 7) { heard += e.word_7 + '*'; } if (noWords >= 8) { heard += e.word_8 + '*'; } if (noWords == 9) { heard += e.word_9 + '*'; } if ((heard.indexOf('*new') >= 0) || (heard.indexOf('*noo') >= 0) || (heard.indexOf('*nude') >= 0)) { recognised = 1; newScan(); } if ((heard.indexOf('*load') >= 0) || (heard.indexOf('*lode') >= 0) || (heard.indexOf('*low') >= 0)) { recognised = 1; loadScan(); } if ((heard.indexOf('*setting') >= 0) || (heard.indexOf('*surf') >= 0) || (heard.indexOf('*secon') >= 0)) { recognised = 1; settings(); } if ((heard.indexOf('*hel') >= 0) || (heard.indexOf('*heal') >= 0)) { recognised = 1; readHelp(); } if (recognised == 0) { var alertDialog = Titanium.UI.createAlertDialog({ title: 'AME SIGHT', message: 'RECOGNISER RETURNED: '+JSON.stringify(e), buttonNames: ['OK'] }); alertDialog.show(); } }); }
Sorry, the Android Emulator Log did not paste in, it is as follows:
D/Window ( 935): Loading window with URL: home.js D/Module ( 935): Loading module: home -> Resources/home.js I/TiAPI ( 935): IN HOME.JS I/TiAPI ( 935): STREAM CREATED D/StreamerModule( 935): (KrollRuntimeThread) [2758,2758] Got Here! I/ActivityManager( 103): Starting activity: Intent { cmp=uk.co.perfecthomecomputers.streamer/.MainActivity } E/TiJSError( 935): (main) [1008,3766] ----- Titanium Javascript Runtime Error ----- E/TiJSError( 935): (main) [5,3771] - In home.js:22,8 E/TiJSError( 935): (main) [5,3776] - Message: Uncaught Error: Unable to find explicit activity class {uk.co.perfecthomecomputers.streamer/uk.co.perfecthomecomputers.streamer.MainActivity}; have you declared this activity in your AndroidManifest.xml? E/TiJSError( 935): (main) [17,3793] - Source: stream.startStreaming(); E/V8Exception( 935): Exception occurred at home.js:22: Uncaught Error: Unable to find explicit activity class {uk.co.perfecthomecomputers.streamer/uk.co.perfecthomecomputers.streamer.MainActivity}; have you declared this activity in your AndroidManifest.xml? D/SntpClient( 103): request time failed: java.net.SocketException: Address family not supported by protocol D/dalvikvm( 350): GC_EXPLICIT freed 102 objects / 6504 bytes in 6644ms W/TiVerify( 935): (Timer-0) [1315,5108] Verifying module licenses... D/dalvikvm( 935): GC_FOR_MALLOC freed 5719 objects / 410120 bytes in 331ms D/TiUIView( 935): (main) [2362,7470] Nativeview is null I/ActivityManager( 103): Displayed activity uk.co.perfecthomecomputers.amesound/.AmeSoundActivity: 27923 ms (total 27923 ms)
Hi Derrick,
I was going to write the solution for you, but you answered your question yourself as in your earlier code you missed the Action to an activity which is the basic need of an Activity to be called from another activity.
You wrote a good code though learned the hard way.
Good luck
Your Answer
Think you can help? Login to answer this question!