Android:app creation malfunction(Implicit Intent) - java

I have two applications where the one opens by implicit intentthe other one.So in the first application I create an Intent and where I wrote i.setAction("com.example.secondApp");and I launch it through startActivity(i);
Then on the second app I change the manifest(filter) like:
<intent-filter>
<action android:name="com.example.secondApp" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
plus I do all the creation intent in the java section.
*code tested because everything was done by explicit intent in the first place and worked fine
So my point is when I try to run them both the first app installs nicely where the second one says that
No Launcher activity found!obviously cause I changed it but despite it installs it isn't shown on the phone nor the first App detects the second one,any clue?
*Also when I leave the manifest(filter) of the second app at default values it installs fine.

If you want an activity to appear in the launcher, it needs the appropriate <intent-filter>:
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
If you want that activity to have another <intent-filter>, that is fine. An <activity> can have as many <intent-filter> elements as needed.

Related

More Classes on Home [duplicate]

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

switching activities when 1 activity is out of memory

so I have an application with multiple activities. So when I switch from 1 activity to another and then click on the back button it works fine. But when I click on 1 activity then go out of the app and go back, it removes the main activity from memory so when you click on the back button, nothing happens. There are 2 possible solutions here, if there is somehow someway to detect if an activity is out of memory or if I can save the activity in memory. This is how I open the activity:
Intent intent = new Intent(context, QuoteActivity.class);
Gson gson = new Gson();
String quoteDataAsAString = gson.toJson(quoteData);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("QuoteData", quoteDataAsAString);
context.startActivity(intent);
And these are the 2 activities:
<activity
android:name=".MainActivity"
android:launchMode="singleInstance"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".quote.activity.QuoteActivity"
android:launchMode="singleInstance"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name=".user.UserFeedBackActivity"
android:launchMode="singleInstance"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
This is what I have in the main view:
#Override
public void onStart() {
super.onStart();
if (QuoteActivity.isChangedWithFavourites()) {
gridView.setAdapter(new QuoteImageAdapater(getApplicationContext(), reader.getCorrectData(currentSection), section));
QuoteActivity.setChangedWithFavourites(false);
}
}
A gif showing it: https://i.imgur.com/YZIkBU1.gifv
And this is how it should be: https://i.imgur.com/hghjB9L.gifv
This problem occurs on both activities even when I don't call the finish method.
Edit: I figured it out I had to change launchMode to singleTop
In Application class, You can override onLowMemory() method.
The documentation says,
This is called when the overall system is running low on memory, and actively running processes should trim their memory usage. While the exact point at which this will be called is not defined, generally it will happen when all background process has been killed. That is, before reaching the point of killing processes hosting service and foreground UI that we would like to avoid killing.
When OnLowMemory is called, Using EventBus you can trigger an event which should be caught by your Activity. Upon which you can perform your desired action.
If you looking to find, If the Activity has encountered OutOfMemoryException(OOM), then follow this answer.
How do I discover memory usage of my application in Android?

Open intent from URL using Java Script is not working on production - DeepLink

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.

How to use non-main activity to capture custom url in unity game?

When someone clicks on a link in a webpage of form "com.foo.bar://testtest" I want it to open my unity game and for me to get the testtest data.
I'm an experienced programmer, but when it comes to android I kind of google my way around rather than really understanding anything. Bare that in mind. :)
I can react to links on android using intent-filters. However all the resources I've found have assumed you can extend your main activity to capture the new intent. It's possible to do that with unity, but for various reasons I'd rather not. I tried creating a new activity, exporting it to a jar, and adding this to my manifest in the application tag:
<activity android:name="com.foo.ProtocolCatcher"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<data android:scheme="com.foo.bar" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
</intent-filter>
</activity>
Clicking on a link successfully launches my game, but onto a black screen.
Edit: I've also tried this format to no change:
<activity android:name="com.foo.ProtocolCatcher"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="com.foo.bar" />
</intent-filter>
</activity>
What are the magic incantations to make the whole game boot, along with my custom activity, and let my custom activity read the incoming URL, without touching the main activity?
I suppose that you are missing a part of the boot sequence; the steps required are the following:
Define the ProtocolCatcher Activity with te proper scheme (OK)
Define the MainActivty, which represents your Unity3D game main Activity (OK)
Start the MainActivity when the ProtocolCatcher Activity gets started (MISSING)
Implementing the third step is super easy; just edit your ProtocolCatcher Activity's onCreate() method:
//ProtocolCatcher
//...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//...
Intent gameIntent = new Intent(this, MainActivity.class);
/*
//Pass the extra data to the game if needed
Intent sourceIntent = getIntent();
Uri data = sourceIntent.getData();
gameIntent.putExtra("uriData", data != null ? data.toString(): null);
*/
startActivity(gameIntent); //start the real game
finish(); //close the ProtocolCatcher activity
}
Considering the fact that you are "injecting" the ProtocolCatcher Activity manually, if you have problem to refer MainActivity from the ProtocolCatcher onCreate() you can lookup the relative Class using reflection.

Android homescreen shortcut permission error

In my program it adds a shortcut to the screen. I get the icon on the screen fine, but when I tap it, I get:
03-01 20:00:29.410: ERROR/AndroidRuntime(796): java.lang.SecurityException: Permission Denial: starting Intent { data=http://www.example.com/ flags=0x14000000 comp={com.isaacwaller.example/com.isaacwaller.example.ExampleCut} } from ProcessRecord{435c7398 796:android.process.acore/10005} (pid=796, uid=10005) requires null
Do you know the problem? Thanks,
Isaac
I had something like this happen when I had accidentally duplicated the activity tag for one of my activities in my manifest. I had something like this in my application section.
<activity android:name=".ConventionHome" android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="ConventionHome"></activity>
When I removed the second activity tag, things started working normally.
Figured it out, added this under <activity> tag of activity:
<intent-filter>
<action android:name="android.intent.action.MAIN"></action>
</intent-filter>
Something like this should work:
<intent-filter>
<action android:name="com.example.Project.Action"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
inside of the Activity declaration in the manifest.
I ran into this problem too, and it turned out it was because the Activity wasn't exposed to other processes. I had to add the android:exported="true" attribute to the activity tag in my manifest.
See http://developer.android.com/guide/topics/manifest/activity-element.html#exported for more information.
I haven't run into this personally but I did do some research and found the following.
Apparently whatever is attempting to invoke your app or if your app has a call to create an intent and start an activity of some intent the UID is not the same.
In ActivityManagerServer.java there are below judgement in it.
int checkComponentPermission(String permission, int pid, int uid, int reqUid)
// If the target requires a specific UID, always fail for others.
if (reqUid >= 0 && uid != reqUid) {
return PackageManager.PERMISSION_DENIED;
}
I'm going to do some testing on this and see if I can reproduce this in a test application and provide any additional feedback.
Make sure you are only trying to invoke publicly exposed activities through any intents.

Categories