Running an android service in kivy written in java - too much? - android

I'm trying to build an NFC card emulator in kivy (similar to https://github.com/okanatas/NFCCardEmulator).
I can't simply subclass HostApduService (i.e.)
from jnius import autoclass
HostApduService=autoclass(android.nfc.cardemulation.HostApduService)
class NfcService(HostApduService):
def processCommandApdu(self, commandApdu, extras):
# Process the incoming APDU command
# and return a response APDU
# Example: Respond with the same data as received
return self.getBytes(commandApdu)
so instead I've tried to include some java files (similar to to the ones in the github) i.e.
package nfccardemulator;
import android.nfc.cardemulation.HostApduService;
import android.os.Bundle;
public class HostCardEmulatorService extends HostApduService {
#Override
public byte[] processCommandApdu(byte[] commandApdu, Bundle extras) {
...
}
}
and some other utilities files in Java.
I've put them in the services/nfccardemulator folder and added the following to buildozer:
android.add_src = services
I've checked the apk, and the classes are compiled and present. But I'm struggling to access them via autoclass
If I say
HostCardEmulatorService = autoclass("nfccardemulator.HostCardEmulatorService")
I get an error instantiating it.
I'm not sure if I'm even setting up a Service like this correctly.
I've seen an example of PythonService i.e.
PythonService = autoclass('org.kivy.android.PythonService')
and then having to use multiprocessing on the service while the kivy process runs separately.
Is what I'm trying to do even possible currently?
Thanks

Related

kivy + android intent filters

Im very new to kivy and python so I may have thrown myself in at the deep end here but i'm trying to figure out how to get an android intent and use it within a simple kivy app?
So im currently trying to figure out the basic design elements and just how to get stuff working. I want to be able to click on a link (for example) and launch my app and then do stuff, nothing too complicated, it just needs to be able to get the link which is passed to it from android.
I figured out this was to do with android intent filters and added the appropriate "intent_filters.xml" file to make this work.
So clicking on the link will launch my app, which is good.
However I cant figure out then how to parse the information passed to the app in android. So below is a very simple app with a button and I just want to update the button to see if my intent is being picked up or not.
Currently clicking the button causes the app to close. When i test this in the Kivy VM I am using to compile the apk it will close with a message that "platform" is not defined (which makes sense as its not in android) but it doesnt much help with testing or tracking down how to make it work.
I've read some stuff which seems to suggest that this might not be possible with kivy?
Can anyone confirm if this is possible in kivy and if so, how?
(i've tried variations on activity.getIntent(), intent.getData(), Intent.getIntent().getStringExtra(Intent.EXTRA_TEXT), Intent().getData().getPath() all to no avail)
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
class TutorialApp(App):
def build(self):
self.gen_btn = Button(text='Initial',
size_hint=(.90, .10),
pos=(5, 5),
font_size=50)
self.gen_btn.bind(on_press=self.update_tutorialapp)
l = BoxLayout()
l.add_widget(self.gen_btn)
return l
def update_tutorialapp(self, *args):
st = update_button()
st.update_Message(self)
class update_button():
def update_Message(self, source):
source.gen_btn.text = "the event was called"
if platform=="android":
from jnius import cast
from jnius import autoclass
import android
import android.activity
# test for an intent passed to us
PythonActivity = autoclass('org.renpy.android.PythonActivity')
activity = PythonActivity.mActivity
intent = activity.getIntent()
intent_data = intent.getData()
source.gen_btn.text = PythonActivity.getIntent().getStringExtra(Intent.EXTRA_TEXT)
if __name__ == "__main__":
TutorialApp().run()
def build(self):
android.activity.bind(on_new_intent=self.on_new_intent) # add this line in build
def on_new_intent(self, intent):
data = intent.getData() # perform operations on intent

Qt/C++/Android - How to install an .APK file programmatically?

I am implementing my own auto-updater within my application. I was able to successfully download the .apk file of the newer version into the /Download folder on the sdcard, but I can't figure out how to open/run that file so the user is presented with the new installation dialog.
The only thing I could come up with:
QString downloadedAPK = "/storage/emulated/0/Download/latest.apk"; // Not hardcoded, but wrote it here this way for simplicity
QDesktopServices::openUrl(QUrl(downloadedAPK));
Debugger output:
D/Instrumentation(26418): checkStartActivityResult :Intent { act=android.intent.action.VIEW dat=file:///storage/emulated/0/Download/latest.apk }
D/Instrumentation(26418): checkStartActivityResult inent is instance of inent:
W/System.err(26418): android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.VIEW dat=file:///storage/emulated/0/Download/latest.apk }
W/System.err(26418): at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1660)
W/System.err(26418): at android.app.Instrumentation.execStartActivity(Instrumentation.java:1430)
W/System.err(26418): at android.app.Activity.startActivityForResult(Activity.java:3532)
W/System.err(26418): at android.app.Activity.startActivityForResult(Activity.java:3493)
W/System.err(26418): at android.app.Activity.startActivity(Activity.java:3735)
W/System.err(26418): at android.app.Activity.startActivity(Activity.java:3703)
W/System.err(26418): at org.qtproject.qt5.android.QtNative.openURL(QtNative.java:110)
W/System.err(26418): at dalvik.system.NativeStart.run(Native Method)
I have looked everywhere but never found anything regarding opening APKs from Qt. The only thing I found was a solutoin using JNI ( which I don't want to use because it's simpler to just do it with C++ and because I have zero experience with the whole C++/JNI thing ) and it was not well documented so I didn't understand how to make it work.
So, what would be the easiest way to open the downloaded apk?
Edit:
I have followed Tumbus's answer, but because of some compiling errors I had to make a few modifications on his JNI code as follows:
void Updater::InstallApp(const QString &appPackageName)
{
qDebug() << "[+] APP: " << appPackageName; // Which is the string ("/storage/emulated/0/Download/latest.apk")
QAndroidJniObject app = QAndroidJniObject::fromString(appPackageName);
QAndroidJniObject::callStaticMethod<jint>("AndroidIntentLauncher",
"installApp",
"(Ljava/lang/String;)I",
app.object<jstring>());
}
When I run my application on my android device, it pulls the newest .apk file from my server, then nothing happens. Why? (I have not made any changes on the AndroidManifest.xml until now).
You have to make a custom intent to install APK. See this question for details.
I'm afraid such platform-specific think must require calls to platform-specific API. The good news are Qt framework has simplified wrap-up on JNI and you can include a Java class into Android project. Therefore I would make my own static java function called from Qt.
Example
Java class
package io.novikov.androidintentlauncher;
import org.qtproject.qt5.android.QtNative;
import java.lang.String;
import java.io.File;
import android.content.Intent;
import android.util.Log;
import android.net.Uri;
import android.content.ContentValues;
import android.content.Context;
public class AndroidIntentLauncher
{
protected AndroidIntentLauncher()
{
}
public static int installApp(String appPackageName) {
if (QtNative.activity() == null)
return -1;
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(appPackageName)),
"application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
QtNative.activity().startActivity(intent);
return 0;
} catch (android.content.ActivityNotFoundException anfe) {
return -3;
}
}
}
Notice that startActivity() should be called as a method from *QtNative.activity(). We have to maintain special directory structures for java according to conventional rules. The example is at Makefile section below.
JNI
The C++ code to call this method is a bit tricky.
const static char* MY_JAVA_CLASS = "io/novikov/androidintentlauncher/AndroidIntentLauncher";
static void InstallApp(const QString &appPackageName) {
QAndroidJniObject jsText = QAndroidJniObject::fromString(appPackageName);
QAndroidJniObject::callStaticMethod<jint>(MY_JAVA_CLASS,
"installApp",
"(Ljava/lang/String;)I",
jsText.object<jstring>());
}
The string literal "(Ljava/lang/String;)I" is the signature of java method.
The name of the Java class must be at a complete form "my/domain/my_app/MyClass"
Makefile
The last challenge is to include the java code to your project properly. Below the corresponding fragment of the .pro file.
android {
QT += androidextras
OTHER_FILES += android_src/src/io/novikov/androidintentlauncher/AndroidIntentLauncher.java
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android_src
}
QMake has a special variable ANDROID_PACKAGE_SOURCE_DIR for this job. Java sources must reside in ANDROID_PACKAGE_SOURCE_DIR/src/my/domain directories.
Also don't forget to add java source to OTHER_FILES and include androidextras QT option.

Sending RIL command on galaxy / nexus

I wonder how can I send commands to rild - not rild-debug.
I have root and the program may be in c / java.
I tried radiooptions
( https://github.com/mozilla-b2g/android-hardware-ril/blob/master/rild/radiooptions.c ).
but radiooptions uses rild-debug and not rild.
I tried to change to SOCKET_NAME_RIL_DEBUG to SOCKET_NAME_RIL
but the program didn't do nothing..
There is any way I can send raw RIL commands ? (Maybe directly from adb ?)
Thanks in advance.
Package:
com.android.internal.telephony
File:
com/android/internal/telephony/RIL.java
Method:
public void invokeOemRilRequestRaw(byte[] data, Message response)
To call the method, using code:
import com.android.internal.telephony.ITelephony;
ITelephony it = ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
it.invokeOemRilRequestRaw(oemReq, oemResp);
or using code(if possible):
import com.android.internal.telephony.PhoneFactory;
((PhoneBase)PhoneFactory.getDefaultPhone()).mCi.invokeOemRilRequestRaw(oemReq, oemResp);
Well, I found a way to do it with xposed:
we can find the class:
com.android.internal.telephony.RIL
find methods in it, and invoke them.

AIDL unable to find the definition of a Parcelable class

I have the following project structure.
My StockInfo.java is perfectly fine.
StockInfo.java (No error)
package org.yccheok.jstock.engine;
import android.os.Parcel;
import android.os.Parcelable;
public class StockInfo implements Parcelable {
...
...
StockInfo.aidl (No error)
package org.yccheok.jstock.engine;
parcelable StockInfo;
StockInfoObserver.aidl (Error!)
package org.yccheok.jstock.engine;
interface StockInfoObserver {
void update(StockInfo stockInfo);
}
AutoCompleteApi.aidl (Error!)
package org.yccheok.jstock.engine;
interface AutoCompleteApi {
void handle(String string);
void attachStockInfoObserver(StockInfoObserver stockInfoObserver);
}
However, Eclipse complains in StockInfoObserver.aidl (It does complain AutoCompleteApi.aidl too, as it cannot process StockInfoObserver.aidl),
parameter stockInfo (1) unknown type StockInfo
I tried for an hour, but still not able to find out, why in aidl, StockInfo is not being recognized although I had
Provided StockInfo.aidl
Provided StockInfo.java
Any idea?
Here are the complete errors.
Note, AutoCompleteApi.aidl is very much dependent on StockInfoObserver.aidl. That's why you will see the error.
I share the entire project for your reference purpose : https://www.dropbox.com/s/0k5pe75jolv5mtq/jstock-android.zip
According to Android documentation You must include an import statement for each additional type not listed above, even if they are defined in the same package as your interface
Try to add this line to StockInfoObserver.aidl
import org.yccheok.jstock.engine.StockInfo;

android jdbc odbc connection

i want to connect odbc connection to my android application. my database is oracle 10g. Here in my code my table name is world. After compiling my program and close the emulator open table in oracle database the values could not be stored
The same coding i compiled normal javac compiler in cmp prompt the values should be stored, if i compiling in android application in eclipse ide the values could not be stored.Pls give one solution or any changes in my code
Thanks in advance
package com.odbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import android.app.Activity;
import android.os.Bundle;
import android.R.id;
public class OdbcActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
try
{
String country="india";
String city="delhi";
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection con=DriverManager.getConnection("jdbc:odbc:world","system","love");
PreparedStatement ps=con.prepareStatement("insert into world(country,city) values(?,?)");
ps.setString(1,country);
ps.setString(2,city);
ps.executeUpdate();
}
catch(Exception e)
{
System.out.println("Exception:"+e);
}
}
}
Android apps connecting directly to a DMBS isn't an architecture I'd recommend. Instead, I suggest setting an application on the server (using Java, Rails, whatever) that reads the database and exposes a simple HTTP web service for the Android app to get at the data. Not only is that a more sound architecture, I'm not even sure you can run JDBC drivers in an Android device. Using my architecture, you isolate the device from the structure and type of your database.

Categories

Resources