intent not available across applications - android

I'm seeing a very strange behavior whereby when I have two separate apps and I side load them (or run them both from Eclipse) and launch one with the other, providing some data in the Intent, the receiving app gets the info.
However, when the apks for these two apps are installed via a browser download (not from the Play store, just downloaded from an internet address, and installed) the Intent on the receiving app comes across as empty.
I'm wondering if I'm overlooking some permission or restriction, and if not, what I can do to get around this problem. I'm LITERALLY not changing anything other than the method of installation and seeing this side-effect, so, I'm pretty sure that this isn't a red herring of some sort. Have tested across a multitude of devices.
The two apps have different package names and aren't related in any way (other than having the same encryption key, though I don't believe that has anything at all to do with the price of tea in China).

So it turned out that I was totally missing a (seemingly) important mechanism for data transfer between Activities, which is documented here:
http://developer.android.com/training/sharing/send.html
and here
http://developer.android.com/training/sharing/receive.html
The sending Activity needs to add the data (in my case Stringfied JSON as)
//...whatever other Intent setup you need
it.setAction(Intent.ACTION_SEND);
it.putExtra(Intent.EXTRA_TEXT, jsonObj.toString());
it.setType("text/plain");
startActivity(it);
And the receiving Acitivity amongst other things that you'll see in the documentation above needs to specify in the Manifest that it's willing to accept such values with this:
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
I hadn't seen this documentation and was passing the data in the totally generic way (just packing Extras into the Intent). The larger question, I guess, is why my generic way worked at all, if there's such a specific way that it's *supposed to work. Obviously my fault for not reading all the documentation and playing along, but it I'm really curious what distinction Android makes between apps that are side loaded via USB, vs. apps that are side loaded from the internet.
Anyway... live and learn.

Related

Answer incoming call using android.telecom and InCallService

Since API 21, Google has been adding features to android.telecom in general, especially by implementing more members of TelecomManager and the addition of InCallService. This last one is is supposed to allow non-system, 3rd-party apps to provide and replace the functionality of the system Calls app in-call screen - the Window that pops up and allows action on EXTRA_STATE_OFFHOOK or EXTRA_STATE_RINGING broadcasts (i.e. incoming and outgoing phone calls).
Currently, only this screen has full control of ringing and active calls and associated system callbacks with fine-grained information, by means of the root-restricted MODIFY_PHONE_STATE permission and a lot of secured AOSP code not even accessible by reflection. It's notably one of the most changed pieces of code in different manufacturers' ROM flavours, together with the launcher, contacts and camera.
This is all very pretty but...
How do you actually develop a 3rd-party InCallService?
Namely:
How do you get notified about, and acquire instances of GSM Calls
How does one answer these calls
What is the life-cycle of the callbacks on this class
Does Google provide any actual tutorial for this that I haven't found
I won't ask answers for all of these at once, but any one answer probably associates to the other questions. This is broad but intrinsically it needs to be: there's no example on the web I've stumbled upon other than AOSP-code, and that code is based on the assumption of root-privileges, which makes it unusable for 3rd-party app development purposes.
How do you get notified about, and acquire instances of GSM Calls
First, the user will need to select your app as the default Phone app. Refer to Replacing default Phone app on Android 6 and 7 with InCallService for a way to do that.
You also need to define an InCallService implementation the system will bind to and notify you about the call:
<service
android:name=".CallService"
android:permission="android.permission.BIND_INCALL_SERVICE">
<meta-data
android:name="android.telecom.IN_CALL_SERVICE_UI"
android:value="true" />
<intent-filter>
<action android:name="android.telecom.InCallService" />
</intent-filter>
</service>
There you should handle at least onCallAdded (set up listeners on Call, start your UI - activity - for the call) and onCallRemoved (remove listeners).
How does one answer these calls
If the user wants to answer the call, you need to invoke the method Call#answer(int) with VideoProfile.STATE_AUDIO_ONLY for example.
What is the life-cycle of the callbacks on this class
Check out Call.Callback for events that can happen with a single call.
Does Google provide any actual tutorial for this that I haven't found
I don't know about Google, but you can check out my simplified example https://github.com/arekolek/simple-phone
Follow the advice from the second comment of Replacing in call app. In addition you need a service that implements the InCallService interface. When a call arrives the onCallAdded(Call call) method will be called, giving you a reference to the call object.
<service
android:name=".InCallServiceImplementation"
android:enabled="true"
android:exported="true"
android:permission="android.permission.BIND_INCALL_SERVICE">
<meta-data
android:name="android.telecom.IN_CALL_SERVICE_UI"
android:value="true" />
<intent-filter>
<action android:name="android.telecom.InCallService" />
</intent-filter>
</service>
Once you have the call object, answering it's as simple as call.answer(). I suggest that when you get the stuff above working, run a couple of test calls to get to know when the different callbacks are invoked.
Regarding tutorials, I couldn't find any when I was looking into this, but that was over a year ago...
Hope this helps!
I guess Google must've read this question, because apparently on Android 8, a new permission finally allows answering calls through a 3rd party dev-facing permission.
android.permission.ANSWER_PHONE_CALLS (...) allows apps to answer
incoming phone calls programmatically
No details yet though, since the documentation for API 26 hasn't been released yet. I'll make sure to update this answer when they do.
EDIT: user arekolek provided an answer that works perfectly on the original API version of this question (at the time of asking, API was 23, even though the question mentions API 21), thus he gets the tick for right answer. Refer to his answer if you want to implement an incall screen that targets minimum SDK of 23. Note you might need API-dependant code or compat library tweaks if you want it to work on more recent APIs that deprecate (or restrict) usage of the provided sample code. the github repo works as I initially intended.
I would recommend you to see this project to build a dialer app for Android.
https://github.com/HiddenPirates/Dialer

How to get all intent filters for application (with root)

I am working on a system application and I need to know programmatically what intents an application is capable of handling. I have seen other questions related to this, but none of them seem to have an answer but also do not seem to be concerned with system privileges.
PackageManager only seems to provide methods to query activities for a given intent. I can not find a way to get intents for a given activity.
For example, if I have an activity which has intent filters defined as such:
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.USER_PRESENT"/>
</intent-filter>
And I know the activities class name and package name, I would like to find out from the package manager (or any other source) what intents it can handle (in this case, BOOT_COMPLETED and USER_PRESENT).
Good question. I don't think it's possible to find out the intents that an app can handle. Some standard activity actions and broadcast actions are listed at http://developer.android.com/reference/android/content/Intent.html. If you are writing your own app that's having it's own intent filters, then i don't think other apps will know what intents your app can handle because there is no way to publish them or announce them to the world, i believe.
But what is possible is that you can make a call for a particular intent and if that returns null, then you know for sure that there are no apps on the device that can handle that particular intent.
HTH.
So after just asking this question, I found this wonderful answer here:
Android — How to I get a list of all available intent filters?
Which leads to this 5 year old issue
So it doesn't seem like there is any way to do what I want to do at the moment. If it becomes available, I would love to know.
you could try a decompiler, such as "DexDump" (available on GooglePlay), and retrieve the "AndroidManifest.xml" of the application you want to know about.

How to manage delivery of NFC tags to multiple apps

I want to create an app that stores a timestamp into the database when I scan my work-batch which contains an NFC tag. This will be done via an IntentService without starting an activity. After a second scan another timestamp will be stored into the database via the IntentService. No activity has to be started. A notification will be enough. The activity can be started manually by the user to see the info.
I have read that there are a lot of different tag technologies. But I like to make my app a bit more universal. So I don't know which kind of NFC tags my clients are going to use. I could listen for all the different tags and let the user pair a tag with a certain task.
This is fine unless there is one NFC app on the phone. But I have another app which uses NFC. And when I scan a tag Android shows me a selection dialog which app may handle the tag. But I don't want this every time I scan a tag. I want to use both apps so I dont select a default for the tags.
So the question is, How can I scan a tag and route it to the right app. So tag A will be handled by app A and tag B by app B without getting the selection box every time.
I was thinking what the best option should be or maybe somebody has a great idea how to solve this.
I have taught of a couple of different solutions:
Use only writable NDEF tags and add a Android Application Record (AAR) to it. So it will launch the right application after scanning. (If there is no NFC app active in the foreground) this will mean that the user is restricted to a tag technology and needs to write it before using.
Let the application listen for all NFC tags and if a tag is not paired to a task forward it to the system again so that other apps can handle it. (Don't know if this is possible)
Write a app which listens for all NFC tags and let the user decide which tag will be send to which application. So when a new tag is received by the application it asks the user which app may handle the tag and stores the default for this specific tag [by ID or something] into a database. So the next time it will route the intent to the default application for this tag. (Or is there already something like this?)
Hopefully this question is a bit clear. Else I'll try to clarify it a bit more if you like ;-)
I really like to hear what you think about this. Or maybe you have some good suggestions? Please let me know.
Thanks in advance.
I've successfully use an application specific URL scheme for this. Let's assume your URL scheme is "kuiperstimestamp".
The tag then should contain a URL like:
kuiperstimestamp://ts/20130506T034536.293
You then create an intent filter for your service that includes a data element:
<intent-filter>
<action android:name="android.nfc.action.TAG_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="kuiperstimestamp" />
</intent-filter>
Since the intent filter is rather specific, you don't get the app selection dialog (unless another app or service has the same specific intent filter which is unlikely).
This approach is less Android specific than using an AAR.

Android - what is the best way of using Activities (best practice)

I'm writing my first Android app and want to pick up good coding practices. I have an Activity which contains the following:
Button btn = (Button)findViewById(R.id.btnPressMe);
btn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
startActivity(new Intent(Main.this, SecondScreen.class));
}
});
or
startActivity(new Intent("net.mysite.MediaPlayer.CLEARSCREEN"));
AndroidManifest.xml:
<activity
android:name=".landingpage"
android:label="#string/app_name" >
<intent-filter>
<action android:name="net.mysite.MediaPlayer.CLEARSCREEN" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
The first way described is best used within your application, the other is used for other application to call your activity.
Abu,
The answer to your question depends largely on what you are trying to accomplish. Keep in mind that the other answers provided thus far have valuable input in regard to making your decision.
The Android Philosophy
Android is designed such that the User ultimately decides which applications take care of which tasks. Applications may overstep them, but should only do so if they are the only ones reasonably able to take care of that task OR if it is necessary for the functioning of the application as a whole.
An Intent marks the User's or the System's or an Application's desire to perform said task. Just because an Intent is made does not require that the User know or initiate it, though often it is best. However, if the Intent is hidden to the User, one might question whether it should be an Intent at all. This is something that is still being worked out by the development community and there are advocates both for and against the practice.
Static Class Intents
startActivity(new Intent(Main.this, SecondScreen.class));
These should be used when you cannot trust another application to handle your desired Task effectively. These kinds of tasks should also be "hidden" from the User, as the User may not care what is happening or who is doing it, so long as it gets done. Additionally, they should only be used for stable code that is not subject to changes. As Snicolas stated (and I personally agree):
Classes can vary in the life of an app.
Action String Intents
startActivity(new Intent("net.mysite.MediaPlayer.CLEARSCREEN"));
These should be used whenever possible. However, they should only be used when the Task can be performed by another application without destabilizing your own application. The Action String can be designed in such a way that it is rare enough to not be called by anyone else, but understand that an Action will prompt the User if more than one Application can handle it.
Analogize the idea similar to: "I use Microsoft Office for Databases and Word Processing, but when I want a Spreadsheet, I use Open Office". Both provide compatible results, but one is preferred for one reason or another. This works because Excel is not required for Word or Access to work correctly. Neither are Open Office's equivalents required for any other working part. They are all installed together but work independantly because they work with different resources and data entirely.
Hope this helps,
FuzzicalLogic
It's better not to use a static class name to call an intent. Classes can vary in the life of an app. Later, if you decide that this activity should change for another class, you would just have to change it in one and only one place if you use the AndroidManifest way.
Also, defining this kind of configuration provides other apps with a way to call your activities to get a service done. And that's the actual power of android to let apps communicate through intents.

How to start a Service when .apk is Installed for the first time

In my Application I am not having any UI part, so I need to start a Service as soon as the Applicaton gets installed on the Device. I saw many links from which the answer was that its not possible but I guess it is surely possible. Just have a look at PlanB Application on the Android Market that does fulfil my requirement. Below is my Manifest file how I tried, but the Service was not called at all. So, let me know what is the best possible way to start a Service when the Application gets Installed.
UPDATE
I also tried using android.intent.action.PACKAGE_ADDED it works fine for detecting the Package for the other Applications but not for itself.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.auto.start"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="8" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<application
android:icon="#drawable/ic_launcher" >
<service android:name=".MyService">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</service>
<receiver android:name=".BootUpReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<category android:name="android.intent.category.DEFAULT"/>
<action android:name="android.intent.action.PACKAGE_INSTALL" />
<action android:name="android.intent.action.PACKAGE_ADDED" />
<data android:scheme="package"/>
</intent-filter>
</receiver>
</application>
</manifest>
Fortunately, Plan B does not work on Android 3.1+, as tested on a XOOM and a Galaxy Nexus.
What Plan B does is exploit a security hole that could be used by drive-by malware, which is specifically why Android prevents it from happening anymore.
UPDATE
To clarify: As inazaruk posted and I put into comments on other answers, all applications, upon installation, are placed in a "stopped" state. This is the same state that the application winds up in after the user force-stops the app from the Settings application. While in this "stopped" state, the application will not run for any reason, except by a manual launch of an activity. Notably, no BroadcastReceviers will be invoked, regardless of the event for which they have registered, until the user runs the app manually.
This block covers the Plan B scenario of remote-install-and-run, which they were taking advantage of previously. After all, with that, anyone with a hacked Google account would be at risk of having their device infected, hands-free as it were.
So, when the OP says:
I need to start a Service as soon as the Applicaton gets installed on the Device
the OP will be unsuccessful and will need to redesign the application to avoid this purported "need".
Applications installed on the /system partition are not subject to being placed into the "stopped" state after installation. If you have root, you can do,
$ adb root
$ adb remount
$ adb push your.apk /system/app
And it can immediately receive broadcast intents. This certainly doesn't provide a general purpose solution, but i wanted to mention it for completeness.
EDIT: Keep in mind that different versions of Android locate system APKs in different places. For example, Android 8 puts them under /system/app//.apk. Shell into your device and poke around and follow the same scheme used for other system APKs.
I agree with CommonsWare's answer to question: How to start android service on installation. In other words, you can't automatically start your service after you've just been installed.
One more thing about newer Android platforms: if you don't have UI at all, you'll have trouble starting your service even when using BOOT_COMPLETE intent on Android 3.1+.
That's because all installed applications are in stopped state. In this state applications will not receive ANY broadcast notifications.
In order to activate your application some other application (or user) needs to start your service or activity, or content provider. The usual workflow is when user clicks on your application's icon.
I've written a detailed explanations about this in my blog post.
Plan B does this launch by listening to the events which happen in the system. It uses a receiver which literally listenes to hundreds of events hoping that some of them will eventually fire up. So this is how you can do it. Otherwise, there are no built-in means to launch the application as soon as it gets installed.
I'm not sure what your constraints/purpose is, but if you can install another application that has an activity you can have it send an intent with the flag FLAG_INCLUDE_STOPPED_PACKAGES.
This will use your application for the intent resolution, even though it's in a stopped state. If the action of the intent matches one of your filters, it will also bring the package out of the stopped state.
I don't think so You can start service immediately after installed your application on device,
The application must first be invoked by the user through some sort of Activity.The only things you have to register some Broadcast Receiver with appropriate intents in manifest which invoke you service when something is happening on device but this remaing to Android 3.1 version.
EDIT:
After Android 3.1+ onwards you can not use any Broadcast for starting your application, because all application remains in inactive state after completion of device boot and to launch the application the user have to invoke it.(By touching the app icon).
As stated by CommonsWare in the answer to this question (which I suppose you have all ready seen, but chose to ignore) starting a Service on install is not possible - it is simply not a thing that is implemented into the platform.
Starting it automaticly at the next boot is however possible.
As stated in the Technical Details for PlanB:
Plan B will attempt to launch as soon as it downloads, but in some cases you will need to send an SMS to get it started.
My guess is that on a rooted phone you might be able to start the Service on install - but there's no guarantee that the phone is rooted, which is why PlanB will require recieving a text in some cases because that can be registered by the IntentFilter of the app and then used to start the Service.
there is an app on google play Android Lost which invoke the registration service for google push messages via an incoming sms without launching the app even once for version 3.0+.
Perhaps the best way to accomplish this (and now I'm speaking to the specific intent of the OP, a program that gets installed in order to retrieve a stolen phone, not the general question) is social engineering, not software engineering.
So, an icon with text like "Password List" or "My Bank Accounts" which suddenly appeared on the home screen would undoubtedly be clicked on. Look at the success of all sorts of other phishing, and here you would be targeting a thief, who's already motivated to continue nefarious activity. Let the thief start it for you. :)
HEY I think using a BroadcastRecivier to automatically start the app on restart of device hence it will automatically start on device start.Hope this will help

Categories

Resources