I have been trying to get two activities in two separate applications to communicate using a custom action and an implicit intent.
The first application (server), has the following manifest:
<application android:icon="#drawable/ic_launcher"
android:label="#string/app_name" android:theme="#style/AppTheme">
<activity android:name="edu.example.sharing.manager.SecureFileShare"
android:label="#string/title_activity_secure_file_share" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="edu.example.sharing.action.STORE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="*/*" />
</intent-filter>
</activity>
</application>
The second application creates an intent as follows:
File f = new File(s);
Uri fileUri = Uri.fromFile(f);
Intent intent = new Intent();
intent.setData(fileUri);
intent.setAction("edu.example.sharing.action.STORE");
startActivityForResult(intent, STORE_REQUEST);
Its manifest is normal. When I try to send the intent in the client application, however, I get an activity not found exception:
FATAL EXCEPTION: main
android.content.ActivityNotFoundException: No Activity found to handle Intent {act=edu.example.sharing.action.STORE dat=file:///storage/sdcard0/Download/Alarcon12-Rigoberto.pdf }
at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1545)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1416)
at android.app.Activity.startActivityForResult(Activity.java:3351)
at android.app.Activity.startActivityForResult(Activity.java:3312)
What's causing Android to not recognize the declared activity in the second application? Thanks.
After much looking, here's what I found:
When you use a built-in action type and attach a data field or when you use a custom action type with no data field, an intent-filter without a data element is ok.
However, when you define a custom action and include a data field, you must manually set the mime-type for the URI attached. The Android documentation claims that
Normally the type is inferred from the data itself. By setting this attribute, you disable that evaluation and force an explicit type.
But that's not the case. When I put in a file:// URI which ended in .txt, Android assigned it a null mime-type, so it wouldn't match any intent-filter, even one with a data and */* mime-type. I needed to manually set the intent's type using setDataAndType().
In short: You must manually define an intent's mime-type when using a custom action with data.
Firstly You can specify only which application to go to; you cant specify which avtivity to go to; I've already answered how to navigate to another app here; after that your control goes to the other app; you have to handle it there
Related
What needs to be done to make your app appear as an option app.
For eg, when I select an image file, android shows me a list of applications to open the file with, like Gallery,Photos etc.
I want that android also shows my app in this list.
How to achieve this? I am unable to understand which android classes to use for it? Or do I need to modify manifest file to add some specific intents?
By defining intent filter you can achieve this. You can register your Android components via intent filters for certain events.If a component does not define one, it can only be called by explicit intents. The key for this registration is that your component registers for the correct action, mime-type and specifies the correct meta-data.
Eg.
<activity android:name=".BrowserActivitiy"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http"/>
</intent-filter>
</activity>
Above code will register an Activity for the Intent which is triggered when someone wants to open a webpage.
Source: http://www.vogella.com/tutorials/AndroidIntent/article.html
We must write an Android app who knows how to open .xyz files.
However when we assign the .xyz files to our application, and after that we tap on an .xyz file in the Android's File Explorer, the application is properly started but the program doesn't see the file name as a parameter.
The code
ShowMessage(ParamStr(0)); //for debug...
ShowMessage(ParamStr(1));
Instead of showing in message boxes the application's full path and after this the full path of the tapped (clicked) file name it shows two empty strings.
How can we get the full path of the tapped (clicked) file?
UPDATE:
(A part of) The manifest looks like this:
<activity android:name="com.embarcadero.firemonkey.FMXNativeActivity"
android:label="MMBook"
android:configChanges="orientation|keyboardHidden">
<!-- Tell NativeActivity the name of our .so -->
<meta-data android:name="android.app.lib_name"
android:value="MMBook" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" android:host="*" android:pathPattern=".*\\.mma" android:mimeType="*/*" />
</intent-filter>
</activity>
You need to call SharedActivity.getIntent() to check if your app was started by an Intent or not. If a non-nil Intent is returned, you can retrieve its data (ie, the filename) and act accordingly. See my answer to the following question for an example:
Handling Custom URI in Delphi XE5 Android App
https://stackoverflow.com/a/20465775/65863
On Android, launching an activity and passing a file from a different app is implemented with Intents and Intent filters. (See Allowing Other Apps to Start Your Activity)
So usually your app must implement an Intent handler. In order to decide what action to take in your activity, you can read the Intent that was used to start it.
The URI of the selected file then can be retrieved with Intent.getData()
Java Example:
// Get the intent that started this activity
Intent intent = getIntent();
Uri data = intent.getData();
// Figure out what to do based on the intent type
if (intent.getType().indexOf("image/") != -1) {
// Handle intents with image data ...
} else if (intent.getType().equals("text/plain")) {
// Handle intents with text ...
}
See also: http://codeverge.com/embarcadero.delphi.firemonkey/android-intent-filter-associate/1057456
I know I need to use to enable an activity to receive an Intent like this (not main activity).
<activity android:name=".MyApp_2ndActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
However, I found it can be triggered too if "intent-filter" is removed, like this.
<activity android:name=".MyApp_2ndActivity">
</activity>
I am wondering what difference is in these 2 formats?
See here: http://developer.android.com/guide/components/intents-filters.html
The difference is the second one can only be started using an explicit Intent -- one which names the component it wants to start. The first one can be started by an implicit Intent -- one which does not specify the exact component but contains information for the system to find an appropriate match for. The intent filters are used by the system for resolving such intents.
Difference is the when we use this code:
<activity android:name=".MyApp_2ndActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
This will be the first activity triggered when you starts your application.It doesnot need any explicit intents
and when we use this code:
<activity android:name=".MyApp_2ndActivity">
</activity>
the activity will be started with the use of Explicit intent
Intent filters are used, for example, when the activity starts from a specific event on the device. Your main activity has specific intent filters. If you want your application start when NFC tag is scanned, you can specify that via intent filters.
You can read more here for example.
http://developer.android.com/guide/components/intents-filters.html
I am trying to start an activity defined in another apk, in its AndroidManifest.xml, it defines an activity and with an action, but no category defined.
The format is like
<activity name="...">
<intent-filter>
<action android:name="action name">
<intent-filter>
</activity>
My code is following
Intent i = new Intent("action name");
startActivity(i);
However my apk crashed with uncaught ActivityNotFound exception, the logs read
No Activity found to handle intent ... "
Any thoughts?
Thanx a lot.
Looking at the Intent documentation, it says Note also the DEFAULT category supplied here: this is required for the Context.startActivity method to resolve your activity when its component name is not explicitly specified. If the activity's IntentFilter definition does not include that category then you can't start it with startActivity. Try using the setClassName method, and pass it the package class and the activity class you're trying to launch.
you cannot have empty category when you use startActivity(...).
add a default category and this will do the job:
<intent-filter>
<action android:name="action name" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
You need to define the activity you are starting in your Manifest. Make sure you have provided same <intent-action (and name of the activity) that has the activity in the other apk you want to start.
android: how do i open another app from my app?
Well I searched a lot, but I didn't find a precise answer how to export an Activity, so an app can start it with startActivityforResult.
How do I achieve that? Do I have to change the Manifest in some ways?
As an alternate to Dalmas' answer, you can actually export an Activity without creating an <intent-filter> (along with the hassle of coming up with a custom action).
In the Manifest edit your Activity tag like so:
<activity
android:name=".SomeActivity"
....
android:exported="true" />
The important part is android:exported="true", this export tag determines "whether or not the activity can be launched by components of other applications". If your <activity> contains an <intent-filter> then this tag is set to true automatically, if it does not then it is set to false by default.
Then to launch the Activity do this:
Intent i = new Intent();
i.setComponent(new ComponentName("package name", "fully-qualified name of activity"));
startActivity(i);
Of course with this method you will need to know the exact name of the Activity you are trying to launch.
You need to declare an intent-filter in your Manifest (I took the following example from Barcode Scanner) :
<activity android:name="...">
<intent-filter>
<action android:name="com.google.zxing.client.android.SCAN" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
Then create an intent with the same action string :
Intent intent = new Intent("com.google.zxing.client.android.SCAN");
startActivityForResult(intent, code);
Android should start your activity (or it will show a drop-down box if there are multiple apps sharing the same action string).