Passing extras from ANE to Flex app - android

I have a flex mobile application with an ANE. This ANE has a broadcast receiver that starts the flex mobile application when it receives an event:
public class BroadcastEventHandler extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
Log.d(Constants.TAG, "BROADCAST EVENT RECEIVED!");
try {
Intent i = new Intent(context,
Class.forName(context.getPackageName()+".AppEntry"));
i.addCategory( Intent.CATEGORY_LAUNCHER );
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.putExtra("nameKey", "value");
context.startActivity(i);
} catch (ClassNotFoundException e) {
e.printStackTrace();
Log.d(Constants.TAG, "Error on starting Intent: "+e.getMessage());
}
}
On the flex application I have the following code:
protected function view1_preinitializeHandler(event:FlexEvent):void
{
NativeApplication.nativeApplication.addEventListener(
InvokeEvent.INVOKE, onInvoke);
}
private function onInvoke(event:InvokeEvent):void
{
trace("Arguments: " + event.arguments);
}
What I want to do is to pass Extras from the broadcastreceiver to the flex application when it is executed (as you can see I added a Bundle object in the ANE code, but I don't receive anything in the flex application):
Trace:
Arguments:
Do you know a way to start activity (in android native) with some parameters/extras and get them in the flex application?

Finally, I could not do this via Bundle object from native code. Passing arguments to an application must be with the <data android:scheme="my-scheme"/> tag in the manifest.
However,
One caveat is that invoking other apps with the custom URL schemes from AIR apps is not possible. The AIR security model is more restrictive and it limits schemes to: http:, https:, sms:, tel:, mailto:, file:, app:, app-storage:, vipaccess: and connectpro:. You can find more about it here and here.
From this great tutorial:
http://www.riaspace.com/2011/08/defining-custom-url-schemes-for-your-air-mobile-applications/
So far, what I have done is implement a class with member data. There, I store the data that I want to handle later (which is the same data that I wanted to pass directly via the Bundle).
public class DataModel {
//data I will get after in the actionscript side of the code
private int notificationCode;
public int getNotificationCode(){
return notificationCode;
}
public void setNotificationCode(int notificationCode){
this.notificationCode=notificationCode;
}
}
When I receive a notification in the broadcastreceiver I set the new value of the notificationCode, and then I start the activity (same as before but adding a call to setNotificationCode function).
Then, in the actionscript side, on the method onInvoke, I do the following call:
//call native functions:
//broadcastevent is the EventDispatcher that connects to the ANE
notificationCode=broadcastevent.getCode();
switch(notificationCode)
{
case Constants.DEFAULT_NOTIFICATION_CODE:
{
notificationMessage="THERE ARE NO NOTIFICATIONS";
break;
}
case Constants.UPDATE_APP_CODE:
{
notificationMessage="UPDATE APP NOTIFICATION";
break;
}
case Constants.SHOW_ALERT_CODE:
{
notificationMessage="SHOW ALERT NOTIFICATION";
break;
}
default:
break;
It is not what I exactly was looking for but I have not found other way to do something similar, and it works!

Related

Implicit Internal Intent vulnerability showing up when Android app is deployed to the Playstore

Recently I have uploaded my android apk on the app store and its been told that the next upload to Google play store will get rejected and we need to check and resolve it. Below is the screenshot of the message:
They are referring to package name also. Below is the code:
#Override
public void onDestroy() {
cleanup();
super.onDestroy();
Intent intent = new Intent("com.test.dummyapp");
sendBroadcast(intent);
}
Please assist me how to resolve this.
Below is the code where the component is triggered:
IntentFilter restartFilter = new IntentFilter("com.test.dummyapp");
registerReceiver(restartBroadcastReciver, restartFilter);
private BroadcastReceiver restartBroadcastReciver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
doBindService();
}
};
When you do this, you are broadcasting an "implicit Intent". This is dangerous because any app can register to get this (potential leak of information) and any app can also broadcast this Intent (triggering your app).
Intent intent = new Intent("com.test.dummyapp");
sendBroadcast(intent);
To fix this you can use LocalBroadcastManager (it is deprecated, but still works). Using a local broadcast ensures that other apps cannot see your broadcast Intent and other apps cannot trigger your app this way.
See https://developer.android.com/reference/androidx/localbroadcastmanager/content/LocalBroadcastManager
As an alternative, you should be able to make the Intent explicit by setting the package name:
Intent intent = new Intent("com.test.dummyapp");
intent.setPackage("my.package.name");
sendBroadcast(intent);
It seems really weird to send a Broadcast in onDestroy. I can't possibly see a use for that, and I can see a lot of problems due to onDestroy being called unexpectedly (rotation, screen size change, etc).
But if you have to do it, use new Intent(getPackageName()). What they're looking for is a hardcoded package name like that. The problem is that if you run 'com.facebook.whateveritscalled' and a piece of malware is installed that named itself that, you would be sending the intent to it. Which if you have extras in the intent could be leaking information to it.
Thanks for the information.
I made some changes to the posted code. Let me know if this works fine.
#Override
public void onDestroy() {
cleanup();
super.onDestroy();
openApp((Context) context,"com.test.dummyapp");
}
public static boolean openApp(Context context, String packageName) {
PackageManager manager = context.getPackageManager();
try {
Intent i = manager.getLaunchIntentForPackage(packageName);
if (i == null) {
return false;
}
i.addCategory(Intent.CATEGORY_LAUNCHER);
context.sendBroadcast(i);
return true;
} catch (ActivityNotFoundException e) {
return false;
}
}

Android - How to receive shortcut create result

Looking at the code sample here - I find the following comment puzzling:
// ... We assume here that the
// app has implemented a method called createShortcutResultIntent() that
// returns a broadcast intent.
what does it mean the app has implemented ... where is this implementation done?
is it a broadcast receiver? registered to which intent filter?
is this an abstract method? of which class?
and then I see this code sample - which handles a completely different flow (I think) and I'm lost again
You can obtain feedback via catching the broadcast event which you setup while use requestPinShortcut function.
At first you need a usual broadcast receiver (in the code below it has name ShortcutReceiver). You can even use existing broadcast receiver and simple add new action which it should catch.
Lets the action will be "general.intent.action.SHORTCUT_ADDED" and it will be stored in ShortcutReceiver.kInstalledAction constant. In this case in the manifest you should have:
<receiver android:name=".ShortcutReceiver" >
<intent-filter>
<action android:name="general.intent.action.SHORTCUT_ADDED"/>
</intent-filter>
</receiver>
After this you can use following code in the activity for create a pinned shortcut (in other places change this on object of Context class):
ShortcutManager manager = this.getSystemService(ShortcutManager.class);
Intent targetIntent = new Intent(ShortcutReceiver.kInstalledAction);
targetIntent.setPackage(this.getPackageName());
PendingIntent intent = PendingIntent.getBroadcast(this, 0, targetIntent, 0);
manager.requestPinShortcut(info, intent.getIntentSender());
In this code info is correct object of ShortcutInfo class.
You can handle the event while catch the broadcast:
public class ShortcutReceiver extends BroadcastReceiver {
public static final String kInstalledAction = "general.intent.action.SHORTCUT_ADDED";
#Override
public void onReceive(Context context, Intent intent) {
if (kInstalledAction.equals(intent.getAction())) {
// Handle the event after the shortcut has been added
Toast.makeText(context, "The shortcut has been added", Toast.LENGTH_LONG).show();
}
}
}
Please take into account that from my experience the broadcast event happens after the shortcut has been added but sometimes there can be some delays (at about some minutes). But may be there is some dependency on the launcher.
Update
As described in other answers on Android 8 catching of implicit intent via broadcast in general doesn't work.
So I simple changed the intent to explicit via set package name of the current app. So only our broadcast receiver can catch the intent.
First things first. Implicit intents on Android 8.0 Oreo:
Because Android 8.0 (API level 26) introduces new limitations for broadcast receivers, you should remove any broadcast receivers that are registered for implicit broadcast intents. Leaving them in place does not break your app at build-time or runtime, but they have no effect when your app runs on Android 8.0.
Explicit broadcast intents—those that only your app can respond to—continue to work the same on Android 8.0.
There are exceptions to this new restriction. For a list of implicit broadcasts that still work in apps targeting Android 8.0, see Implicit Broadcast Exceptions.
https://developer.android.com/about/versions/oreo/android-8.0-changes
Note: there are some exceptions: https://developer.android.com/guide/components/broadcast-exceptions (very few)
Instead, we will use the so-called context-registered receiver, it will last as long as our app lives, or until we unregister it.
Also, ShortcutManager requires API 25 that's why we will use it's compat version in order not to duplicate the code for old and new versions. (ShortcutManagerCompat was added in version 26.1.0)
Code to create a pinned shortcut on the Home screen:
public static void addShortcut(Context context, String id) {
if(context == null || note == null)
return;
//there may be various Home screen apps, better check it
if (ShortcutManagerCompat.isRequestPinShortcutSupported(context)){
Intent shortcutIntent = new Intent(context, MainActivity.class);
shortcutIntent.setAction(Constants.ACTION_SHORTCUT); // !!! intent's action must be set on oreo
ShortcutInfoCompat shortcutInfo = new ShortcutInfoCompat.Builder(context, note.get_id().toString())
.setIntent(shortcutIntent)
.setShortLabel("MyShortcut") //recommend max 10 chars
.setLongLabel("Long shortcut name")//recommend max 25 chars
.setIcon(IconCompat.createWithResource(context, R.drawable.ic_shortcut))
.build();
//callback if user allowed to place the shortcut
Intent pinnedShortcutCallbackIntent = new Intent(ACTION_SHORTCUT_ADDED_CALLBACK);
PendingIntent successCallback = PendingIntent.getBroadcast(context, REQ_CODE_SHORTCUT_ADDED_CALLBACK,
pinnedShortcutCallbackIntent, 0);
ShortcutManagerCompat.requestPinShortcut(context, shortcutInfo, successCallback.getIntentSender());
}
And here is the code to receive the broadcast in your Activity, for example. Note that this "callback" will be called only if your app is running, receiver is registered and the user allowed the shortcut:
private ShortcutAddedReceiver shortcutAddedReceiver;
private void registerShortcutAddedReceiver(){
if(shortcutAddedReceiver == null){
shortcutAddedReceiver = new ShortcutAddedReceiver();
}
IntentFilter shortcutAddedFilter = new IntentFilter(ShortcutHelper.ACTION_SHORTCUT_ADDED_CALLBACK);
registerReceiver(shortcutAddedReceiver, shortcutAddedFilter);
}
private void unregisterShortcutAddedReceiver(){
if(shortcutAddedReceiver != null){
unregisterReceiver(shortcutAddedReceiver);
shortcutAddedReceiver = null;
}
}
#Override
public void onStart() {
super.onStart();
registerShortcutAddedReceiver();
}
#Override
public void onStop() {
super.onStop();
unregisterShortcutAddedReceiver();
}
private class ShortcutAddedReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
Snackbar.make(view, "Shortcut added", Snackbar.LENGTH_LONG).show();
}
}
Hope this helps!

Ibm mobile first: Is there a way to send events even though app is killed

I am building an Application using Ibm Mobile First. In which I need to sync-up some data with server whenever the device gets the Internet connection.
To achieve this I have implemented a broadCast receiver in Android Native.
public class ConnectivityReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
boolean isConnected = BasicUtils.isConnected(context);
L.e("onReceive : "+isConnected);
Config.isConnected = isConnected;
try {
JSONObject data = new JSONObject();
data.put("isConnected", isConnected);
WL.getInstance().sendActionToJS("isConnected", data);
} catch (Exception e) {
// TODO: handle exception
}
}
}
I am using this method WL.getInstance().sendActionToJS("isConnected", data) to send Data to Js which is working fine when app is running but not working when the app is killed.
So is there a way I can send some event from Android native to js when the app is killed or not running?
What you're looking for is rubbing the mobile first SDK as a Service in Android.
Unfortunately at this time the SDK is not available for a Service in Android.

Receive message SmartEyeglass ControlExtension

I want to make an app for Sony SmartEyeglass where the App on the Phone and the ControlExtension exchange data on runtime.
It's pretty obvious how to send messages from the app to the extension...
public void startExtension(String msg) {
if (HelloWorldExtensionService.Object != null) {
HelloWorldExtensionService.Object
.sendMessageToExtension(msg);
}
}
but how do I get the msg in my ControlExtension, if the extension is already running?
I didn't find an onMessageReceived(String message) method for the class ControlExtension.
You can do this using Intents the same way you would for an standard Android app. For example from your Activity:
Intent intentBuzz = new Intent();
intentBuzz.setAction(buzzIntent);
mContext.sendBroadcast(intentBuzz);
Then in your Control Extension register a broadcast receiver:
buzzReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
buzzAction();
}
};
registerReceiver(buzzReceiver, new IntentFilter(buzzIntent));
This works the other way around as well if you want to pass something other than a string.

Create an IntentFilter in android that matches ALL intents

Is it possible to create an IntentFilter in android that matches ALL intents that are Broadcasted on the phone (perhaps by way of using a BroadcastReceiver)? I.E. the ones I see in ddms when I use the phone, under the ActivityManager tag? After digging through the documentation, and looking at the framework source, I am left to think it can't be done? That you must specify some sort of data, to paraphrase the docs, "some sort of data must be specified, or else you'll only get intents with no data". The app I am writing needs to know about every app that is started on the system. So far, the only way I have been able to do this is by polling ActivityManager. It seems the best way would be to have an event driven solution, using whatever underlying logic ActivityManager uses, but it's all greek to me inside of the ActivityManager.java framework source, and seems like a lot of the stuff underneath (if not ALL) is deliberately encapsulated from me.
Any ideas?
You said it yourself, the documentation quite clearly specifies how intent filters function and that this is not possible to receive all broadcasts.
Neither this nor retrieving task information is something that is supported by the APIs made public in the Android SDK.
You can register a costume receiver for each event type that will hold a reference to a parent broadcast receiver and call its onReceive method
class ChildBroadcastReceiver extends BroadcastReceiver {
private BroadcastReceiver parent;
public ChildBroadcastReceiver(BroadcastReceiver parent) {
this.parent = parent;
}
#Override
public void onReceive(Context context, Intent intent) {
parent.onReceive(context, intent);
}
}
Then you can register to all the possible events by using reflection:
final BroadcastReceiver parent = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
android.util.Log.d("GlobalBroadcastReceiver", "Recieved: " + intent.getAction() + " " + context.toString());
}
};
Intent intent = new Intent();
for(Field field : intent.getClass().getDeclaredFields()) {
int modifiers = field.getModifiers();
if( Modifier.isPublic(modifiers) &&
Modifier.isStatic(modifiers) &&
Modifier.isFinal(modifiers) &&
field.getType().equals(String.class)) {
String filter = (String)field.get(intent);
android.util.Log.d("GlobalBroadcastReceiver", "Registered: " + filter);
application.registerReceiver(new ChildBroadcastReceiver(parent), new IntentFilter(filter));
}
}

Categories

Resources