Context
Our app shows an HTML flashcard to the user.
We have added several layers of "filters" to satisfy different groups of users:
To satisfy chess enthusiasts, we convert any {FEN:rnbqkbnr/pp1ppppp/8/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R b KQkq - 1 2} block to an HTML table representing a chess board with pieces at the right position
To satisfy Chinese language learners, we convert 字 to <ruby>字<rt>zì</rt></ruby>
...
Original HTML → Chess transformation → Chinese transformation → ... → Final HTML to display
Problem
The number of filters is growing, leading to problems:
Slower rendition
Heavier download
Bigger source code to maintain
More bugs/crashes
Maintenance burden
Question
So, we would like to make these separately installable apps.
For instance, a chess+Chinese enthusiast would install 3 apps:
TheApp
TheApp Chess plugin
TheApp Chinese plugin
TheApp would automatically discover what plugins are installed, and call them in turn (order does not matter).
I was thinking of using an intent THEAPPTRANSFORM, but how can I receive the list of apps that have an <intent-filter> for THEAPPTRANSFORM, and call them all in turn?
Speed is a major requirement. I have read that Intents are 10+ times slower than direct calls... would Parcelable help here?
If impossible, is there any other solution?
To know apps which have a broadcast reciever with THEAPPTRANSFORM as filter, you can use below code
PackageManager pm = getPackageManager();
Intent intent = new Intent("THEAPPTRANSFORM");
List<ResolveInfo> info = pm.queryBroadcastReceivers(intent, 0);
for (ResolveInfo resolveInfo : info) {
Log.e("apps", "packages = " + resolveInfo.activityInfo.packageName);
}
You need a dynamically installed plugin which is not part of your application. I think you have a few options for this.
Solution 1: Scripting
Ship a scripting language interpreter with your app. (eg. ruby - http://ruboto.org/). Create an interface for executing these scripts. Make a central database of such scripts, or load them from external storage. Now, you can execute these scripts and get the required result.
Solution 2: AIDL
Use a remote service in the plugin apps. Provide an AIDL for third parties to develop apps with a remote service with that AIDL. Such services should also conform to an intent filter defined by you. Now you can use packagemanager to find such services, select one and connect to it. Now you can call all the AIDL methods. This will be inter process communication using binder, for your application this will be a synchronous call. (see this SO question for details - Access remote service in different application)
Downside to this approach is that all these services need to be running when your app is running, so you have to handle the starting/stopping of these services. It will also affect the power consumption if the services are running in the background.
Solution 3: Broadcast/receiver
Third party installed apps that have a broadcast receiver with an intent filter for custom intent defined by you. Also, your app needs to have a broadcast receiver with a custom intent that the plugins can call with the result. Now, say you want to call a third party plugin for some transformation, you have to do this:
Use packagemanager to find all the third party apps conforming to
your custom intent. Send a broadcast with extradata about
transformation. Handle the transformation in the broadcast receiver of
the plugin app. Once transformation is done, send a broadcast with
result to the original app.
This option is entirely asynchronous, and it may take any amount of time to execute with no guaranties.
Related
Everyone knows Tasker.
The optimal way to use Tasker would be to create a Plugin. But then you can't use other automation Apps like Llama (except you also build a plugin for them of course).
I saw a clever workaround for this. since nearly all automatisation Apps are able to start Intends, some Apps like the one for Franco.Kernel or ElementalX have classes which can be startet from such Apps to do Stuff. For ElementalX it looks like this: flar2.elementalxkernel.powersaver.DISABLE_POWERSAVE.
I like this idea and want to implement this to!
but I have some questions...
Are these just normal classes like every other Activity and Class in my Project?
How do I get my Context in those Classes?
Can those classes access all other functions and SharedPrefs in my App?
Is it possible to hand over parameters like Ints or Strings?
What else do I need to keep in mind?
The example you gave is an intent from the application ElementalX Kernel (now replaced by EX Kernel Manager)
The intent is made public by adding android:exported=“true” to the app's manifest. This means other apps like Tasker can use it.
Within the ElementalX Kernel app, there is a broadcast receiver that listens for this intent. When the intent is used, it triggers further actions. In your example, when the intent flar2.elementalxkernel.powersaver.DISABLE_POWERSAVE is broadcast, the app will receive the broadcast and call the methods that disable powersave mode.
I read this question and another question and I understand how to launch an application from another application (Let's call the other application LauncherApplication). However, my goal is not only to launch an application, but to use its functions, so I suppose the LauncherApplication should start an activity using an intent (explicit or implicit).
I should know the data and the actions the installed applications react on and I should add these information to an intent instance before starting it. I wish LauncherApplication allows the user (not the developer) to configure this intent, but how do I know in advance the parameters to put in an intent for the installed applications?
I should implement the "LauncherApplication* in order to allow the user to construct an intent via a graphical interface. Or I could make my application supports the addition of plugins: in this way, I could create a plugin for each installed application, where each plugin could be responsible to manage the configuration of the intent concerning the application associated with it.
UPDATE (added details). In particular, the LauncherApplication should be a service with a speech recognizer enabled, so the user may start an application uttering specific keywords: as well as launch an application, the user should be able to close it and use its functions.
For example, I could have installed an application ((Let's call it LibraryApp) to search for available books in a library; this application could have the following functions:
Search for a book (this function may return if the book is available, it has already been loaned or if it was booked by someone else).
Reserving a book (this function should return the completion of the reservation).
In this way, when I pronounce, for example, the words "start LibraryApp", then the LauncherApplication service should launch the LibraryApp application. Once the application is launched, the service should be able to send commands to it to use one of the available functions (search for a book, reserving a book).
How can I send commands to application that is already active, in order to control it?
how do I know in advance the parameters to put in an intent for the installed applications?
You talk to their developers. There are typically zero "parameters" on an Intent to launch the launcher activity (or activities) of an application, since home screens do not put such "parameters" on the Intent.
I am working on the security aspects of my android application.
I would like to know about the ways to secure the Intent data and extras while sending it from one application to another so that no other application other than these two can snoop it.
One of the brute-force approaches would be to use android's encryption-decryption to encode intent data, is there a better way to achieve the same ??
Thanks in advance.
As pointed in the other answers, although you can send an intent to a fully qualified activity, nothing prevents someone from creating an application with the same package.
You might want to add an additional security step to this scheme:
First send a 'Challenge' intent to the remote activity (it should, for example, encrypt a random string you provided using a shared passphrase and send it back to you).
If that first security step is ok, you may freely send unencrypted messages to this remote app by using its fully qualified activity.
This is rather lame security, but perhaps it's sufficient for your needs.
Please take a look at CommonsWare's comment below.
A more secure way might be to code your activity as a Bound Service, keeping the Challenge step, but by means of more private communication.
My guess is that if you use an explicit intent, i.e. specifying the class to which the intent is to be sent to, then no other class can intercept that intent and look at its data.
This method however, may fail if the class name in the application that you're trying to send the information to changes.
If an intent specifies the the target, which is part of the sender application's package, then other applications won't have the chance to capture it - it will be delivered to the intended receiver.
On the other hand, if you send an intent to another application, there is no guarantee that the receiver of the intent will have the implementation you expect: if you send your intent to com.mycompany.security.SecureReceiver, but instead of your application, another application is installed with the given class description, than you will send your intent to that application.
Also, Android is an open system. If someone compiles his own application framework, than he can manipulate the Intent delivery system.
Do you want to protect your data from the user, or from malicious applications?
I've built an app called xLancer (https://market.android.com/details?id=kz.jay.xlancer.activity) that retrieves job listings from Elance. Now i want to implement a feature that would remind me to bid on a project at a later time. Instead of reinventing the wheel i want to launch any external TODO/Task manager app. But now i am stuck, i don't know which URI or action should be specified, so far i've only used intents to call my internal activities by specifying class name explicitly.
So the question is: how can i know which URI/action should be specified?
Look here, I didn't see any Todo/Task intents there though....
If I want to create custom address book (which overrides my phone's default address book), and if I want it to be used by all applications, what should be my intent-filter? Does Android allow me to do such a thing considering the fact that such a third-party app could potentially be malicious?!
And, if I want to have yet another address book application, I suppose the second app also has same intent-filter, isn't it? How does the framework decide which app to pick if I click on Contacts button when making a call? In other words, how does the framework resolve intents in case,there is a conflict between multiple intent-filters?
You can replace any application on Android platform, even Home. Android documentation explains everything there is to know about Intents and Intent Filters and there is a section called Intent Resolution that answers your question. Intent Resolution section for Intent class has some additional information.
As far as I can tell Android doesn't try to resolve a conflict. It ask the user which application to run and gives them the choice to mark this Activity as the default for this Intent. They give an example about mail app here.
While Mr. Smiljanić is basically correct, there is no Contacts application in Android for you to replace. There is Dialtacts, which is the application supporting the contacts, call log, and dialer. That application cannot be replaced, mostly because the dialer cannot be replaced.
So, while you may be able to override some intent filters and get control on some contacts-related requests, you will be unable to get the contacts portion of Dialtacts overridden, which will confuse users.