Tested on Pixel 3a (both emulator and physical device (my used device)) API 30 (11.0).
Repo:
https://github.com/amdreallyfast/AndroidStartOnBootExample
Goal:
I'm trying to launch an android app on startup, but failing.
Note: I am well aware that this should not be done for apps designed for the general public. This is not that. At the moment, this is just concept exploration for a personal project. The larger goal is to tinker with a used Pixel 3a and turn it into a home utility device. I don't want to start the app manually every time I need to turn it on and would rather have it starting automatically, so I'm trying to find a way to launch the app at startup.
Also Note: Because this is a project to start on boot, I can't use the debugger for most of this and have to rely on notifications instead to detect progress.
Progress:
I've got a BroadcastReceiver that responds to the BOOT_COMPLETED intent by launching a Service. The service's onCreate(...) function creates a simple intent to start another app (at the moment, just Google Maps, which is readily available without additional software installation).
I've also got MainActivity, a simple program that has a button that uses an intent to launch the same Service. I use this to compare behavior between starting the service at startup and starting the service from an already-running activity.
Already tried setting the intent flag Intent.FLAG_ACTIVITY_NEW_TASK.
Problem:
Google Maps does not launch from the service when called during startup. I know that the service's code is correctly set up to launch the map intent because launching the MainActivity and pressing the button will launch the service and then start Google Maps just fine. I also know that the code running on startup got through to the point where it launched the map intent because notifications indicate as such.
The only difference that I'm noticing between not working and working seems to be the manner in which the service is started.
Documentation:
I found this android docs page: https://developer.android.com/guide/components/activities/background-starts. It says (in part):
Apps running on Android 10 or higher can start activities only when one or more of the following conditions are met:
The app has a visible window, such as an activity in the foreground.
<other possible conditions>
Why doesn't this start? Am I misunderstanding this? Google Maps most certainly has a visible window, so I am expecting to be able to start it.
Note: Again, I'm not planning on releasing my app to the general public. This is just for me.
The larger goal is to tinker with a used Pixel 3a and turn it into a home utility device
Write a launcher app (i.e., have your activity respond to ACTION_VIEW/CATEGORY_HOME) and set it as your default launcher. It will automatically start when the phone starts, just as your current default launcher does. And, you can put a button or something in your own launcher that launches the real launcher via an explicit Intent.
This would allow you to skip the on-boot receiver and the service.
Why doesn't this start?
You do not qualify for a background activity start.
Google Maps most certainly has a visible window, so I am expecting to be able to start it.
First, presumably it does not have a visible window right after boot.
Second, you are not writing the Google Maps app, and Google Maps is not trying to start an activity from the background. You are writing your own app, and your own app is trying to start an activity from the background. And, since your own app does not have a visible window right after boot, it does not qualify for a background activity start under the "app has a visible window" rule.
Following up on the answer by #CommonsWare, here is my activity's configuration in my app's manifest file (just for the sake of completeness):
<activity
android:name="com.example.androidstartonboot.MainActivity"
android:launchMode="singleTask"
android:stateNotNeeded="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Note: Strictly speaking, launchMode and stateNotNeeded are not necessary for MainActivity to successfully launch on startup, but my understanding is that it is good practice to add them to a launcher. Documentation: https://developer.android.com/guide/topics/manifest/activity-element
To enable:
Run the app (or run the debugger) to install.
Press the "Home" button (solid dot on Android 11). Android should present an option for which app to use to respond to the LAUNCHER intent. There should be two options: "Pixel Launcher" (the Android default) and the app who's MainActivity is configured as above.
Select your app and choose "Always use this app".
Now, every time you press the "Home" button, your app should run.
Note: To restore the "Pixel Launcher" as the default launcher:
Swipe down from top
-> Settings
-> Apps & Notifications
-> All Apps
-> Pixel Launcher
-> Advanced
-> Home (should say "No" at this point)
-> <choose "Pixel Launcher">
This was tested on Android Studio Bumblebee | 2021.1.1 Patch 2, in a Kotlin project.
Note: This does not work if there is also a BroadcastReceiver that the manifest is configuring to respond to the intent filter <action android:name="android.intent.action.BOOT_COMPLETED". I tried it. Disabling the BroadcastReceiver allowed this to work. Re-enabling it prevented MainActivity from launching on startup. So that needs to be commented out/removed before this launcher will work.
Related
I have many "internal" activities in my Android application that I only want to be started from inside my application by code I've written. These "internal" activities have no intent-filter tag in the Android manifest file. I have one activity, named SplashActivity, that I use as a splash screen that has the typical launch intent-filter:
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
I was hoping/expecting that whenever Android launched my app and created my custom Application object, it would always start my SplashActivity. However, some of my users have encountered launches where one of my "internal" activities which have no intent-filter are started. I believe that activity was typically the last activity used in a previous invocation of the app. I have not been able to reproduce the issue myself. However, is there some scenario where Android will launch my app, creating my custom Application object, but starting one of my internal activities that has no intent-filter. Under what circumstances will Android do so?
To easily reproduce the scenario where Android application launch starts an activity that has no intent-filter, first open your application to any such activity. Press the Home button. Then using Android Device Monitor (DDMS) to find the process that is running your application and stop/kill that process. Then launch your app. Android will create your Application object but will start/restore the activity that was last displayed instead of the starting the one with the MAIN LAUNCHER intent-filter.
Android can kill the OS process hosting your app at any time. Usually this happens when your app has been in the background for a while (ie: the user navigated away from your app to go do something else). This happens all the time.
When the user then returns to your app, Android creates a new OS process for the app, and creates a new instance of the Activity that was on the top of the stack (ie: the Activity that was showing on screen before the app was pushed to the background).
If you don't want this to happen, you can add the following attribute to the <activity> declaration for SplashActivity:
android:clearTaskOnLaunch="true"
This will force Android to always restart your app from the beginning if your user returns to it. However, this might make your users complain, because if the user is using your app, then takes a phone call, then returns to your app, it will start from the beginning again.
It is better if you detect the problem yourself, and redirect to the SplashActivity only when necessary (ie: when your app needs to be initialized because the process has been killed and restarted). To do this, declare a static variable named initialized in SplashActivity that you set to true when your SplashActivity has successfully initialized the app. In every other Activity, do this in onCreate():
super.onCreate(savedInstanceState);
if (!SplashActivity.initialized) {
// Android killed my process, need to redirect the user to `SplashActivity`
redirectIntent = new Intent(this, SplashActivity.class);
startActivity(redirectIntent);
finish();
return;
}
This happens when the application is still "alive".
When you exit an application, Android does not kill it. It will remain there until the memory is needed.
In this case, when the use re-launches it he will get the last Activity.
Can you try adding
android:clearTaskOnLaunch
for the root activity in your manifest file.
When android device power on, is it possible to load one specific application without launching home screen?
How to make this change?
Where to change code
Setting permission as boot_completed works but before my application is loaded, the homescreen is shown for 5 seconds. How to disable android from showing any homescreen launcher before my application
This mode is called kiosk mode, and android has provision for running devices in Kiosk mode, you can refer to this guide for the complete set up. Basically what you do is set up your app to listen to the RECEIVE_BOOT_COMPLETED broadcast and disable all actions such as back button home button minimize buttons etc. Also don't forget to set up an exit mechanism. Just follow the guide and you should be fine.
In your manifest:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
And add Intent filter:
<receiver android:name=".BootReciever">
<intent-filter >
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
And then Now you can start your application's first activity from onReceive method of Receiver class:
https://stackoverflow.com/questions/10428510/how-to-start-launch-application-at-boot-time-android
For more information you can check this url How to start/ launch application at boot time Android
if your device has been rooted, uninstall system applications on your device, but be careful that every app can not be uninstalled. install "Root-Uninstaller-Pro-8.3" app and do this. you must uninstall important system apps one by one and any time restart your device to see result until Achieve goal. if you uninstall an app that make your device Messed up, you should flash your device to restore apps and retry uninstallations. by this uninstallations, your boot time become too short and that 5 second will be disappear. good luck!
I want to build an app for android and ensure that the user can only use this app. (i.e. user should not be able to open or install any other app.)
Is it possible to force such restrictions on an Android device ? And if it is where should I start ?
What you are looking for is called the "kiosk mode" (just to help you googling the appropriate term).
There is no such thing in the standard android api (at least... not yet : see the Edit). User always have the ability to press the home button to come back to the Home application.
But solutions exists:
Writing an Home app
This solution is a little weak (but may fit your requirements ?) : develop a "Home application" (it's very easy : just put something like this in your manifest :
<activity android:name="MyCustomHome"
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
With this, when the user press the home button : he will have to choose the Home app to use, and if the user decide to make your app it's default Home : he will always came back to your app when pressing the Home button.
Drawback : the Home button is not the only way to get out of the current app, and so this solution won't really block the user (for instance : on samsung, swipe from top to bottom always display the toolbar... and the user can do anything from there)
Using specific constructor extensions :
samsung-knox is a solution for recent samsung devices (warning : it's a huge and complex security solution for enterprises : many components to do many things and I think you need to be a samsung partner to get acces to kiosk-mode api)
for motorola : there is an app called EnterpriseHomeScreen that can be used to run your own app in kiosk-mode
I guess other solutions exists for other constructors, but I'm not aware of them.
EDIT/UPDATE
With Android-5.0-Lollipop : the screen pinning api allows you to run your app in kiosk-mode. The android terminology for kiosk-mode is screen-pinning-mode.
To make your app working in screen-pinning-mode, you must use Activity.startLockTask (and Activity.stopLockTask() to quit the screen-pinning mode).
By default the user must approve the screen-pinning-mode (a popup will be prompted when your app call startLockTask).
If your app is a device owner : then the user won't be prompted and your can go in screen-pinning-mode without confirmation.
The user can also enable screen-pinning-mode for an app manually by choosing : Settings > Security > Screen Pinning. (in this case: the user can exit screen-pinning-mode by holding both the Back and Recent buttons)
Set up Single-Purpose Devices Page of android developer have described this things you can easily get to know more things from there.
I am creating a cross platform app in Adobe Flex with AIR 3.3 SDK. For Android, I have created a native extension which launches a native android activity with a simple view in it by firing an Intent.
The issue is that when we minimize the app and resume it by either choosing the app icon from apps menu or by long pressing home button to get list of recent apps, Android automatically calls the onDestroy of the native android activity and kills it. The same scenario works perfectly fine on Android 4.0. The problem is happening only on Android 2.x devices. We haven't been able to test honeycomb yet.
After reading the Android documents, I understand that onDestroy is either called when someone calls finish on the activity or if the device is running low on space. And, to distinguish between the both, one can use the isFinishing() method. This would return true if activity has been destroyed by calling finish.
In our case, in the scenario described above, activity's finish function is not called. onDestroy is called when the app resumes but isFinishing() still returns true. This suggests that the app is not low on memory. I have tried adding all kind of Flags to the intent but nothing changes the behavior.
I have no idea from where else can the onDestroy function be called? I need to figure out a way to stop the native activity from being destroyed on app resume.
The code to launch the native activity is something like this:
Intent intent = new Intent("android.intent.action.K12");
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra("params", parameters);
context.getActivity().startActivity(intent);
The entry for the activity in the manifest goes like this:
<activity android:name="com.k12.main.MainActivity">
<intent-filter>
<action android:name="android.intent.action.K12" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
I have read a lot of blogs and SO questions but could not get around this issue. Please help.
I want to detect each time the user opens the app, by tap on home / desktop icon. There seem not to be a straight forward way to do it. Found a few workarounds but nothing seems to be really reliable.
Things like, extend application object and use method "onCreate()", but this is not what I need because it's not called always when the user taps on the app's icon (can be just brought from the background, launching doesn't necessarily recreate the application), and also the application may be destroyed and recreated while running. Then Application.onCreate() will also be called.
There war also some approaches involving BroadcastReceiver and checking intent flags but everything seems to be also not quite reliable?
I need this because I want to track with Google Analytics, when the user opens the app.
Thanks
Whenever your application is launched by normal way [if user taps on icon on home launcher] then main Activity for which
<activity
android:name=".xyz"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
is defined, in this application onCreate method will surely be called. So here you can put you Google Analaytics tracking code.
In other ways, like broadcast receiver it really depends upon which activity is called upon and whether it is start of application. There too you can put in onReceive method
As far as i feel, Android has definate way of start an app, and its always reliable. Only lifecycle of Android are bit tricky.
Try to look into "android application lifecycle".
But onResume is launched every time you start your activity
Else try : onStart which is called every time your application has been sent to "background". It really does state so in the developer docs.