If I would use the following code:
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(takePictureIntent,1);
it would start the default Android camera app right... I've written a custom camera app, but how do let Android know that it's a camera app, and that the user should be given the choice which Camera app to use.
In other words, if I used the code above, my app should start, and not the default android one.
but how do let Android know that it's a camera app, and that the user should be given the chose which Camera app to use.
Have an <intent-filter> on an <activity> for that action:
<intent-filter>
<action android:name="android.media.action.IMAGE_CAPTURE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
The next time that somebody executes your above startActivityForResult() call, you will appear in the chooser alongside anything else that supports that Intent structure.
Related
I have seen so many different confusing explenations..
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
What is the meaning of
<action android:name="android.intent.action.MAIN" />
and
<category android:name="android.intent.category.LAUNCHER" />
and
<category android:name="android.intent.category.DEFAULT" />
ACTION_MAIN is considered an entry point for the application. Usually, it combines with CATEGORY_LAUNCHER in an <intent-filter> to indicate an activity that should appear in the home screen's launcher, or in anything else that considers itself to be a launcher. Such "launchers" can query PackageManager, using queryIntentActivities(), to find such activities and display them to the user.
However, ACTION_MAIN can be used in combination with other categories for other specialized purposes. For example, CATEGORY_CAR_DOCK with ACTION_MAIN indicates an activity that should be considered a candidate to be shown when the user drops their phone into a manufacturer-supplied car dock.
When an Intent is used with startActivity(), if the Intent is not already placed into a category, it is placed into CATEGORY_DEFAULT. Hence, an <activity> <intent-filter> needs to specify some <category>, using <category android:name="android.intent.category.DEFAULT" /> if nothing else.
android.intent.action.MAIN means that this activity is the entry point of the application, i.e. when you launch the application, this activity is created.
From the docs
ACTION_MAIN with category CATEGORY_HOME -- Launch the home screen.
Also,from here
Activity Action Start as a main entry point, does not expect to
receive data.
android.intent.category.DEFAULT is mainly used for implicit intents. If your activity wishes to be started by an implicit intent it should include this catetory in its filter.
If your Activity might be started by an implicit Intent when no specific category is assigned to it, its Intent filter should include this category.
android.intent.category.LAUNCHER
category -- Gives additional information about the action to execute.
CATEGORY_LAUNCHER means it should appear in the Launcher as a top-level application
See the docs..
http://developer.android.com/reference/android/content/Intent.html
http://developer.android.com/guide/topics/manifest/action-element.html
<action android:name="android.intent.action.MAIN"/>
Is the main activity for this application
<category android:name="android.intent.category.LAUNCHER" />
It is in the LAUNCHER category, meaning it gets an icon in anything
that thinks of itself as a “launcher”, such as the home screen
<category android:name="android.intent.category.DEFAULT" />
The call to startActivity() will always add the DEFAULT category if
no other category is specified.
Generally just add android.intent.category.DEFAULT even if you have other Categories. This will guarantee that if Requesting Intent doesn't provide any Categories while starting the intent using startActivity(intent), then your Receiving Activity can also receive those Intents..
Source: The Busy Coders Guide to Android Development
https://commonsware.com/Android/
The answers above are pretty good, so I will just fill in some of the blanks.
<action / > element
So we all know that when the android system opens our app, it will send out an Implicit Intent and as the documentation states:
the Android system finds the appropriate component to start by comparing the contents of the intent to the intent filters declared in the manifest file of other apps on the device. If the intent matches an intent filter, the system starts that component and delivers it the Intent object.
Now each intent-filter specifies the type of intents it accepts based on the intent's based on the intent's <action>, <category/> and <data/>
So with <action>and <category/> we are defining the name and category of the intent our activity can accept
I am trying to open a website with chrome app from my android app. However, i am not getting any response each time i click the button which link to the code below:
public void openWebsite(View view) {
//Get the url text
String url = mWebsiteEditText.getText().toString();
//Parse the URI and create the intent
Uri webpage = Uri.parse(url);
Intent intent = new Intent(Intent.ACTION_VIEW, webpage);
//Find an activity to hand the intent and start that activity.
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}else{
Log.d("ImplicitIntents","Cant handle this");
}
}
i learned and follow the code from here https://codelabs.developers.google.com/codelabs/android-training-activity-with-implicit-intent/index.html?index=..%2F..android-training#3 and below is some of the message i noticed in the Logcat in android studio when i click the button to open the link:
2020-08-08 01:21:23.651 767-2753/system_process I/AppsFilter: interaction: PackageSetting{cc102 com.example.implicitintents/10160} -> PackageSetting{bbc8e62 com.android.chrome/10129} BLOCKED
2020-08-08 01:21:23.652 31691-31691/com.example.implicitintents D/ImplicitIntents: Cant handle this
The app should open chrome just as shown here: https://codelabs.developers.google.com/codelabs/android-training-activity-with-implicit-intent/index.html?index=..%2F..android-training#5
Pardon me if the question i asked is duplicated.
I think you might be missing some things in your manifest file. Did you follow this part of the tutorial? What does yours look like?
https://codelabs.developers.google.com/codelabs/android-training-activity-with-implicit-intent/index.html?index=..%2F..android-training#6
in particular this part:
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http"
android:host="developer.android.com" />
</intent-filter>
also I think you will need the internet permission to access websites so I would add this too:
<uses-permission android:name="android.permission.INTERNET" />
What permission do I need to access Internet from an Android application?
Hope this helps a bit!
So I programmed an NFC tag to launch my application that I'm currently working on. I used the following service to do that:
https://play.google.com/store/apps/details?id=com.wakdev.wdnfc&hl=en
What I want to do is to switch from one activity to another whenever the NFC tag opens my application.
Under the manifest tag in my AndroidManifest.xml I have:
<uses-permission android:name="android.permission.NFC" />
<uses-sdk android:minSdkVersion="10"/>
<uses-feature android:name="android.hardware.nfc" android:required="true" />
And my MainActivity looks like this:
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
Since the NFC tag opens the MainActivity first, I want to see whether it's been opened by NFC. If it has, switch to another activity.
The problem is that getIntent().getAction() always returns android.intent.action.MAIN while I'm expecting android.nfc.action.NDEF_DISCOVERED.
At the moment I'm performing this check (debugging basically) under onResume() method with the following code:
#Override
protected void onResume() {
super.onResume();
System.out.println(getIntent().getAction());
}
And I've tried performing this check under onCreate() and onStart() methods. All of them return android.intent.action.MAIN result while I expect android.nfc.action.NDEF_DISCOVERED.
I'm fresh in Android development and I'm just trying to make this work for a small prototype. Would appreciate if you guys could help me!
Edit: I got it working! I researched this question a lot and I believe that my NFC tag needed some extra data of a text/plain type (I did not specify this mimeType before as well so seems like it's mandatory). I also had put NDEF_DISCOVERED under LAUNCHER category while trying to debug the application and then changed it back to DEFAULT. I'm finally getting my desired results!
getIntent() returns the Intent that was used to create the activity. In your case, that is the home screen launcher Intent.
When you scan the NFC tag, a new Intent will be delivered to that activity. That Intent is passed to an onNewIntent() method that you can override.
Depending on how your activity is being used, you might need to handle both cases:
Where the user launched your app by scanning the NFC tag, so your activity was created with the NDEF Intent
Where the user launched your app by other means before scanning the NFC tag, so your activity was created with some other Intent and you get the NDEF Intent in onNewIntent()
I have a little mystery here, I have this code in my onCreate method:
Intent intent = getIntent();
if (Intent.ACTION_VIEW.equals(intent.getAction())) {
Log.i(TAG, "ACTION_VIEW START");
Uri uri = intent.getData();
SharedPreferences.Editor tEditor = getSharedPreferences("UserFormPreferences", MODE_PRIVATE).edit();
tEditor.putString("GuestRoomNumber", uri.getQueryParameter("h"));
tEditor.putString("GuestSurname", uri.getQueryParameter("a"));
tEditor.apply();
//it shows an alert to the user
GuestLogin(uri.getQueryParameter("h"), uri.getQueryParameter("a"));
Log.i(TAG, "ACTION_VIEW END");
}
And I have this code in my manifest:
<activity
android:name="epinom.jm.smarthotel.vcMainScreen"
android:label="#string/title_activity_home"
android:launchMode="standard"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="epinom.jm.smarthotel.vcMainScreen" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<data android:scheme="com.guestperience" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
And from a web page I'm executing this JS:
window.location = "com.guestperience://?h=x&a=x";
So here comes the funny part, if I plug my phone, and then in Android Studio, I click on the Play or Debug button, and then I go to the Mail App and tap over a hyperlink that takes me to my web page in Chrome that have the JS instruction, it opens My App and open the intent using the onCreate and onStart method like I expect and add it to the stack of intents in My App, this means that if I'm on any intent of my app and I execute the JS, the app comes to the front and it creates the intent and do what it is supposed to do and shows an alert to the user.
But if I pull the plug or I use the .apk that I have in the Play Store in Beta, this functionality does not work, and I don't understand the difference because to me is the same code, so this is what happens when I'm not connected to Android Studio:
If the app is close, I click on the link, it opens Chrome and the the app is started, and the first intent of the app that is the same that I'm calling, do what it is supposed to do and shows the alert.
Once the app is open if I repeat the steps it never shows the intent and it does not matter if I'm in the initial intent or in another intent.
I have tried to change the code to the onStart but it is almost the same behavior:
If the app is close, I click on the link, it opens Chrome and the the app is started, and the fist intent of the app that is the same that I'm calling, do what it is supposed to do and shows the alert.
Once the app is open if I repeat the steps it only shows the alert when I'm in the main intent (the same that I'm calling), if I'm in another intent it never shows the intent, but if I navigate to the intent the Alert is shown every time I call it. (on every onStart, this can be controlled with a bool).
At the end, I don't understand why the behavior is different when I'm plugged to Android Studio.
Maybe is some permission that I'm missing or something that I have to configure, but I'm lost.
Any help will be appreciated.
Thanks.
UPDATE 1:
I have detected this:
If I plug the phone and press play and keep the plug everything works like a charm.
If I plug the phone and press play and remove the plug everything works like a charm.
If I plug the phone and press play and close the app (the plug can be plugged or not) if I start the app with the link works like a charm, but if the app is started stops working on any intent.
There is something that Android Studio is doing that makes it work, I'm thinking that it has to be with permissions but I'm really lost.
UPDATE 2:
I have tried all the options of this examples and I still have the same result, if the app is open i can't get to the intent, but if the app is closed or is plugged to Android Studio works like a charm.
<!-- Allow web apps to launch Barcode Scanner by linking to http://zxing.appspot.com/scan. -->
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="http" android:host="guestperience.com" android:path="/Main"/>
</intent-filter>
<!-- Support zxing://scan/?... like iPhone app -->
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="com.guestperience" android:host="Main" android:path="/"/>
</intent-filter>
I have tried to attach it to the launcher intent and nothing seems to work.
<category android:name="android.intent.category.LAUNCHER"/>
I have tried to launch the app from an href, to see if a user action is needed and still the same result.
CLICK HERE TO LOGIN
https://developer.chrome.com/multidevice/android/intents
https://github.com/zxing/zxing/blob/master/android/AndroidManifest.xml
UPDATE 3:
I have added this to track the action that is called once the app is open:
Log.i(TAG, intent.getAction().toString());
If I open my app for the first time the value is:
"com.guestperience://Main/"
But if I open another intent and open the app through the link again the result is the last action I have called i.e.:
"epinom.jm.smarthotel.vcMainScreen"
And of course if I open the app with Android Studio I always get this value:
"com.guestperience://Main/"
Because all the app is configurable through JSON files all my activities have intent filters so all my calls are like:
Intent tIntent = new Intent("epinom.jm.smarthotel.vcMainScreen"); //replacing this "epinom.jm.smarthotel.vcMainScreen" with the JSON string var of course
startActivity(tIntent);
finish();
I have read this too, and as far as I can tell I'm not missing anything:
http://developer.android.com/intl/es/training/app-indexing/deep-linking.html
After doing a lot of tests and reading a lot, I have ended doing a base class that extends Activity and my Main Activity extends from the Base Activity.
public class BaseActivity extends Activity {
}
public class vcMainScreen extends BaseActivity {
}
Then on the onStart() of the Base Activity I have added this code to handle the call from the browser:
#Override
protected void onStart() {
super.onStart();
Intent intent = getIntent();
if (Intent.ACTION_VIEW.equals(intent.getAction())) {
Uri uri = intent.getData();
SharedPreferences.Editor tEditor = getSharedPreferences("UserFormPreferences", MODE_PRIVATE).edit();
tEditor.putString("GuestRoomNumber", uri.getQueryParameter("h"));
tEditor.putString("GuestSurname", uri.getQueryParameter("a").replace("/",""));
tEditor.apply();
Intent tIntent = new Intent("epinom.jm.smarthotel.vcMainScreen");
tIntent.putExtra("Login", "true");
startActivity(tIntent);
finish();
}
}
As you can see it calls the Main Activity an there in the onStart() I have added this lines to call my login method:
#Override
protected void onStart() {
super.onStart();
if (getIntent().getExtras() != null && getIntent().getExtras().getString("Login") != null && getIntent().getExtras().getString("Login").equals("true")) {
SharedPreferences tPrefs = getSharedPreferences("UserFormPreferences", MODE_PRIVATE);
GuestLogin(tPrefs.getString("GuestRoomNumber", ""), tPrefs.getString("GuestSurname", ""));
getIntent().putExtra("Login", "false");
}
}
And in the Manifest I have added this code:
<activity
android:name="epinom.jm.smarthotel.BaseActivity"
android:label="#string/title_activity_home"
android:launchMode="singleTask"
android:screenOrientation="portrait">
<intent-filter>
<data android:scheme="com.guestperience" android:host="Main" android:path="/"/>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name="epinom.jm.smarthotel.vcMainScreen"
android:label="#string/title_activity_home"
android:launchMode="standard"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="epinom.jm.smarthotel.vcMainScreen" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
Is important that the Base Activity has a launchMode="singleTask", and a the end I have to use a URL like this:
CLICK HERE TO LOGIN
And I'm using this GIT to handle my DeepLink with some changes:
https://github.com/hampusohlsson/browser-deeplink
I'm sure that this is not the correct way of doing this, but I hope this helps someone in the future.
Happy coding to all.
I currently have an app that has a Share Via button on images, I was wondering if it's possible to maybe somehow add a button to the camera itself that allow to take a picture and pass it to my activity?
I know I can make an activity which takes an image from within my activity and then get the image, but I was wondering if there's a way to add it to the stock camera.
Thanks
You can only register to the share intent from the gallery:
<intent-filter ...>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
</intent-filter>
This will allow your users to take pictures, than share to your app from the gallery (not from camera app)
For obvious reasons, you cannot add a button for your app only in stock camera app.