How to launch a Android Service when the app launches? - android

I'm still fresh to Android and Id think the below config works for launching my service when the app launches.
<service android:name=".PlaylistUpdaterService">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</service>
But this is not the case. What did I miss?

Wrong! extend the Application class (IE make your own), then in the onCreate() method do this.
//Service is below
Intent serviceIntent = new Intent(getApplicationContext(), PlaylistUpdaterService.class);
startService(serviceIntent);
And take that intent filter crap out of your declaration in the manifest file. Leave it as
<service android:name=".PlaylistUpdaterService">
The intent filter following needs to be in your home activity only
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
The reason you do this is because the Application class is started up as soon as the app is, and acts as kind of a global class the the android framework manages.
Actually if you want the service to run every time you go back to your home screen, you should start the service in your home classes onResume(). Putting it in the applications onCreate() will only start the service if the user is launching for the first time, or after the running process has been killed. Or you could put it in your home classes onCreate() but that is not even guaranteed to run every time.

Correct me if I am wrong, but android.intent.category.LAUNCHER is valid only for Activity. So, does not look like valid way to start Service. The same you can achieve if you do the following:
create transparent Activity that will be used only to start Service
for that Activity, you do not need to specify GUI layout. So, you do not need to setContentView() in the activity's onCreate(). The only thing you need is to put
#android:style/Theme.NoDisplay
under Theme tag for this Activity in AndroidManifest.xml.
start Service from onCreate() of your Activity.
call finish() in onStart() of your Activity to close it.
So, your Activity will be invisible to the user, last shortly and nobody will notice that it was used to start the service.

Related

Main activity inside trusted web activity

I started to use Trusted Web Activiy and everything is fine.
Now I want to install Push Notification library and my push ntification service provider needs to add a block of code in MAIN ACTIVITY.
From other hand, I need some check before user start visiting my website like:
Does She/He have an Interet Connection
Is Her/Him google chrome up to date
Get Her/Him device Id
and etc...
So, I need manuplate a splash screen and Main Activity, but I don't know where is main activity to do stuff as I'm newbie to this.
Would you please let me know how should I solve this issues?
Thanks in Advance
You can add a new activity, say MainActivity, which will start at application startup instead of TWA activity and do any additional processing in it's onCreate() method. In the end of onCreate() method you can activate your TWA activity with the intent like this:
startActivity(new Intent(this, com.google.androidbrowserhelper.trusted.LauncherActivity.class));
To make MainActivity the one which opens at application start you will have to remove intent filter from your TWA activity in AndroidManifest.xml and place it into your MainActivity:
<activity android:name=".java.MainActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Some more details in this post: https://stackoverflow.com/a/58069713/8818281

Android handling click on notification

I have this situation in my app: I have these activities
<activity
android:name=".presentation.view.start.view.activity.StartActivity"
android:screenOrientation="sensorPortrait"
android:theme="#style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".presentation.view.main.view.activity.MainActivity"
android:configChanges="locale"
android:screenOrientation="sensorPortrait"
android:theme="#style/AppThemeMultiStep"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".presentation.view.firstScreen.view.activity.FirstScreenActivity"
android:screenOrientation="sensorPortrait"
android:theme="#style/AppThemeMultiStep"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".presentation.view.signup.view.activity.LoginViaPinActivity"
android:screenOrientation="sensorPortrait"
android:theme="#style/AppThemeMultiStep" />
StartActivity acts as a sort of "router" based on the application state:
If I am not logged in, it will launch FirstScreenActivity
If I am logged in, it will launch LoginViaPinActivity, which will login the user based on some logic and then launch MainActivity. At the end of all, MainActivity will be at the root of the activities stack.
At some point the app will receive a notification, and when I tap it I want this:
if the app is running and MainActivity is running, open MainActivity (this is easy, there are planty of ways I can to that with various flags) but if it's not running launch StartActivity (so that I can open the app based on all the startup logics implemented there).
So the options I can think of are:
know if an activity is running in order to fire an intent or another (I don't like static fields solutions like you read in many SO post related to this)
make StartActivity the root of the task and find a combination of intent flags which will act like "launch StartActivity, but if it is running at the root of a task, bring that task to front" (this would be my preferred option if possible)
any suggestion is very appreciated
How do you usually handle this kind of situations? (I don't think I'm the first in the world with this problem :) )
Here is my approach -
Make StartActivity as your router as you've said. Just make launchmode to singleTop in your manifest in order to user onNewIntent() method of an Activity.
You'll generate notification, sending some data with contentIntent - as a result clicking on notification you'll be redirected to StartActivity.
Two cases here -
If StartActivity is in stack
onNewIntent gets called with your new Intent - Choose your activity required to be open - If it is already in stack Bring it to front using FLAG_ACTIVITY_REORDER_TO_FRONT flag
If StartActivity is not running or not in stack
Receive bundle of intent that is being got from the intent via notification, parse data and open an activity accordingly.

BroadcastReceiver instead of Activity

I have an application that doesn't have any activities. All it does is show a notification. Is it possible to put launcher filter on the BroadcastReceiver instead of the main activity?
Here is what I've tried:
<receiver android:name=".LaunchReceiver">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</receiver>
It doesn't work. The app installs, but there is no icon in the launcher.
If it's not possible, are there any other ways to not show the activity? Currently I just have an empty activity and call finish() from onCreate(), but the it still shows up for a split second, which doesn't look nice.
A Receiver receives broadcasts only. Only an activity belongs in the launcher. Intents and filters explains much of this.
To make an invisible activity (to not see it while you quickly finish() it) declare it with this theme:
#android:style/Theme.Translucent.NoTitleBar
But you better also add the following if you have an invisible activity (to avoid confusing the user):
android:noHistory="true"

Child Activity gets killed after parent activity is finished

I have 2 apps, one of them is calling an activity from the second one through an intent filter like so:
Call in App1 (Parent app)
Intent openApp = new Intent("com.app.intent.Activity2");
startActivity(openApp );
Intent filter in App2 (child app)
<activity
android:name=".app.activity.Activity2"
android:label="#string/app_name"
android:launchMode="singleInstance"
>
<intent-filter>
<action android:name="com.app.intent.Activity2" />
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
At one point the Parent application has to close but the problem is the Activity2 from the second application gets killed as well. I can see that Activity2 is actually running under the same package, is there any way to have the Activity2 persist and run even after the parent applicaiton is closed ?
Thank you
This discussion seems to have what you need. Seems like you need to get the launch intent from the package you want to launch and use that in your intent.
Launch an application from another application on Android
Android will generally run all components from the same APK in a single process, so if one of those crashes the process then they will all be gone.
You can however tell it to put an activity or service in its own process.
<activity
android:name=".app.activity.Activity2"
android:label="#string/app_name"
android:launchMode="singleInstance"
android:process=":my_unique_process">
Of course if your process is dieing unexpectedly, that's a problem that needs to be understood and fixed - this would just be a temporary workaround.

How can I make sure Android Beam doesn't start a new instance of my 'singleTop' activity?

First, the use case : 2 phones have my app opened on the same screen. I want one user to be able to share the screen content (data) with the other one without necessarily opening a new instance of the activity when beaming using NFC.
(both Android devices are running Ice Cream Sandwich)
So I have a singleTop activity declared like this in the manifest.
<activity android:name=".activity.MyActivity" android:configChanges="orientation|keyboardHidden" android:launchMode="singleTop">
<intent-filter android:label="#string/activityLabel">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="a.b.c/x.y.z" />
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="application/x.y.z"/>
</intent-filter>
</activity>
When a VIEW action is fired and the activity is already on top, the onNewIntent() method is called in the same instance if the activity.
When a NDEF_DISCOVERED action is fired and the activity is already on top, the onCreate() method is called in a new instance of the activity.
You describe the case that the app is already open and the proper Activity is in the foreground. In that case, you can make use of the foreground-dispatching of NFC intents by calling NfcAdapter.enableForegroundDispatch() in your Activity's onResume() (and disableForegroudDispatch() in onPause()). This will force all NFC Intents to be delivered to your Activity (via onNewIntent()).
I don't have an answer for you. But I have a workaround: have the NDEF_DISCOVERED start a new activity. Make that activity invisible (Theme.NoBackground) and in the onCreate, make it start the MyActivity with singleTop and finish immediately. MyActivity should now appear with onNewIntent.
Have you looked at the Android Beam sample:
http://developer.android.com/resources/samples/AndroidBeamDemo/index.html
It implements this behavior that you want (minus VIEW intent filtering). I'm not sure if that intent will affect the NDEF_DISCOVERED one, but it would be interesting to maybe modify the Android Beam sample to see if you can cause the same behavior as your app.
You should use: android:launchMode="singleInstance"
Works for me.

Categories

Resources