The application that I am working on connects successfully with a device over the USB connection.
Additionally, it now remembers the device from different launches as also pointed out in the following thread storing usb default connections.
However, this leaves the undesired effect of always launching the Activity when the USB device is attached. I have not been able to remember the defaults without launching the application. Launching the application on a connect is not a desired effect. Small code samples below are what the manifest currently looks like in order to get the default USB connections stored in memory for future connections at a quick glance. Can this storage of defaults be done without causing an application launch?
<activity
android:name="com.MainScreen"
android:theme="#style/Theme.Default"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="#xml/device_filter" />
</activity>
I had been thinking that perhaps there was a type of category that I could add to the intent filter that would specify it as a non-launchable intent. Something that was listened for during the activity, but handled by the activity. So far, I haven't found this however.
Update:
Declaring the intent for usb device connection within a service or a receiver in the manifest has also been an attempt at storing connection information. However, only the intent within an activity remembers connection state so that it doesn't need to ask the user a subsequent time when it is re-connected at a later given point in time. It looks as though it is designed only to save state combined with launching an application when it is connected. A bit odd, but no workaround for getting a no-launch combined with remembering the default connection for usb attached device.
You don't have to launch an activity always. You can let a background service handle the intent quietly.
<service android:name=".MyService">
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
</service>
Update:
You might have to request some permissions explicitly. Here's what you should do:
When user installs the app and open it first time, ask for USB related permissions.
Set a service to handle USB attach event as mentioned above. When attached, display a persistent notification in status bar as long as a recognized device is attached.
The status bar notification is also useful to notify user that more permissions are required and main UI activity can be accessed.
You should make a small re-design.
Create a Service and run the logic like 'When USB device attached' etc. (probably you have them in that Activity now) within this service.
By the way, you can always make good use of your MainActivity from or apart from this service.
I can confirm by my own experiments that the USB device will not be remembered from within a service. It seems that requestPermission() must come out of an Activity.
To avoid the launch of the activity, I implemented onPostCreate() like this:
#Override // from Activity
public void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
Intent triggerIntent = getIntent();
if (triggerIntent != null) {
if ( ! triggerIntent.hasCategory(Intent.CATEGORY_LAUNCHER) ) {
Log.e(LOGTAG, "not started by launcher! exit now.");
finish();
}
}
}
I used onPostCreate() instead of pasting the code into onCreate() because when calling finish() from onCreate() it will cause onDestroy() to be called immediately and typically not all members of the Activity class are setup properly yet. It seems to be more safe to me using the onPostCreate() approach.
Related
UPDATE
I'm noticing that I actually am receiving the NETWORK_LOGS_AVAILABLE intent! The problem is, it's taking a very long time (over an hour?) to receive it.
Is there any known way to increase the frequency of receiving these events?
Original Question
I am trying to process DNS events that can now be read after receiving the onNetworkLogsAvailable intent in a DeviceAdminReceiver application. This functionality was made available as of Android 8.0.
For some reason, I am never receiving this intent, even though I am successfully calling the setNetworkLoggingEnabled method. Upon admin being enabled, I am receiving the ACTION_DEVICE_ADMIN_ENABLED event, but nothing else after that.
Here's where I enable network logging:
public class NetworkAdminReceiver extends DeviceAdminReceiver {
#Override
public void onEnabled(Context context, Intent intent) {
DevicePolicyManager manager =
(DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
if ( manager == null )
{
throw new IllegalStateException("Unable to get DevicePolicyManager");
}
if (manager.isDeviceOwnerApp(context.getPackageName())) {
manager.setNetworkLoggingEnabled(getWho(context), true);
}
else
{
Toast.makeText(context, "This application is not device owner. DNS logging only works" +
" when this application is setup as the Device Owner", Toast.LENGTH_LONG).show();
}
}
// *snip* rest of class
}
Although I am not sure whether it's required (cannot find in documentation), I've also added the NETWORK_LOGS_AVAILABLE intent action to the receiver's filter:
<receiver android:name=".admin.NetworkAdminReceiver"
android:label="#string/device_admin"
android:description="#string/device_admin_description"
android:permission="android.permission.BIND_DEVICE_ADMIN">
<meta-data android:name="android.app.device_admin"
android:resource="#xml/device_admin" />
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED"/>
<action android:name="android.app.action.NETWORK_LOGS_AVAILABLE"/>
</intent-filter>
</receiver>
The application is marked as the device owner, network logging is enabled, and yet I never receive the intent. The only explanation I could think of is that network logs do not become available very frequently, but I could find no documentation supporting this theory.
I am also currently only testing this in the emulator. I am unsure if that would have an effect on this, though I cannot see how it would.
Is there anything that I am missing in order to properly receive the network logs via the DeviceAdminReceiver?
I'm afraid there's no elegant solution.
This limitation looks like it was made intentionally. As you can see in the sources, the event is triggered when hard-coded thresholds are reached. It's either 1200 events or 1.5H timeout, whichever comes first. I did not manage to find any usable hooks in the NetworkLogger. They definitely did not want users to meddle with it.
The only option I see is to use reflection to get access to the hidden API.
The most straightforward, IMHO, is to get a handle to the IIpConnectivityMetrics service and use it to subscribe to the network events. I did not test this solution myself, though.
It seems like you can now force retrieve log for debugging purposes as described here: https://developer.android.com/work/dpc/logging#development_and_testing
Quote from the documentation:
While you’re developing and testing, you might want to receive onNetworkLogsAvailable() callbacks without having to browse hundreds of web pages. In Android 9.0 (API level 28) or higher, you can make a few sample network requests and force the system to send a logs-available callback. Run the following Android Debug Bridge (adb) command in your terminal:
adb shell dpm force-network-logs
The system limits how frequently you can use the tool and reports any intentional slowing in the terminal output. If there aren’t any logs to retrieve, your DPC doesn’t receive a callback.
If my app crashes (reason is unimportant - could be hardware issue, out of memory, whatever), Android always starts my app on the last activity. The app is used by people visiting an office for appointments. When the customer arrives, reception unlocks the app using a code for that client and then the client proceeds through several activities. So, there's client context that is needed for all activities in the app except the initial unlock screen. As a result, the app needs to return to the start screen if the app crashes for any reason, but Android always returns to the last activity.
It seems like this should be really easy to do, but Android "helpfully" restarts the last activity used, which can't proceed without the client context. Rather than write a bunch of code to detect if the app has restarted after a crash, I'd rather it just returned to the main activity each time. I've looked at the clearTaskOnLaunch and launchMode manifest options, but they don't seem to work after crashes. I have an UncaughtExceptionHandler on every thread, but certain crashes (e.g. in native code) just terminate the app without invoking it.
Yeah, I could bundle the client state up and restore it after a crash, but I don't want to serialize potentially sensitive information, and this seems like something the OS would just support since it sounds so basic.
Ok, now waiting for someone to tell me some incredibly obvious solution that I've missed...
Thanks.
The obvious (LOL)Put android:clearTaskOnLaunch="true" in your mainifest:
<activity android:name=".StartActivity"
android:clearTaskOnLaunch="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
savedInstanceState() is used when an Activity is forcefully terminated by the OS and other things i.e.:
when your Activity is in the background and another task needs resources
application crash
orientation change
NOT when user press's the "force close" button in settings
When this happens, onSaveInstanceState(Bundle outstate) will be called and it's up to your app to add any state data you want to save in outstate.
The data is held in memory only while the application is alive, in other words this data is lost when the application closes normally.
The not so obvious stuff (brute force approach [unsubtle])
After crash, check the savedInstanceState object on onCreate method of ALL activity's that might crash, and if it is not null (means it is restarted by android system) then finish the activity (maybe relaunch ?).
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState != null) {
finish();
}
}
NOTE An activity also gets restarted in configuration changes (e.g. rotation), so if you use auto rotation you need to live with restart or code for it (not too hard).
Advanced stuff
Use UncaughtExceptionHandler() on every android java thread AND native ExceptionHandler() code if you use native (maybe with JNI callback to java).
I have an application that uses NFC. When the Activity is created and enableForegroundDispatch() has been called, the NFC is scanned and accepted by my application. However, when the NFC is scanned DURING rotation (meaning the Activity has not been created yet, and enableForegroundDispatch() was not yet called), the default Android NFC scanner takes over displaying the "New tag collected" screen.
Is there any way to carry over the enableForegroundDispatch() even during device rotation? Or is there a way to temporarily "block" the default Android NFC capability when the device is being rotated?
Thanks
EDIT: The application only accepts the NFC scan when it is running. Scanning the NFC while the app is not running only displays a "New tag collected" screen
There's different possibilities:
Set screen orientation for your activity
<activity android:name=".MyActivity"
android:screenOrientation="portrait"
android:label="#string/app_name">
Tell android not restart activity when device rotation :
https://developer.android.com/guide/topics/resources/runtime-changes.html#HandlingTheChange
If your application doesn't need to update resources during a specific
configuration change and you have a performance limitation that
requires you to avoid the activity restart, then you can declare that
your activity handles the configuration change itself, which prevents
the system from restarting your activity.
<activity android:name=".MyActivity"
android:configChanges="orientation|keyboardHidden"
android:label="#string/app_name">
UPDATE 1
If you use applying android:configChanges. You have to manage yourself screen rotation as explained in doc :
Now, when one of these configurations change, MyActivity does not
restart. Instead, the MyActivity receives a call to
onConfigurationChanged(). This method is passed a Configuration object
that specifies the new device configuration. By reading fields in the
Configuration, you can determine the new configuration and make
appropriate changes by updating the resources used in your interface.
At the time this method is called, your activity's Resources object is
updated to return resources based on the new configuration, so you can
easily reset elements of your UI without the system restarting your
activity.
I not sure if this can be done.
I want to develop a website and keep it in the device always, without the possibility of exit. I mean disabling the hardware/software buttons and only being able to power off/on. When you reboot automatically will be launch the app. I think this can be done rooting the phone or something similar, but I don't know how can I start. Any idea?
Maybe this cannot be done with a HTML page, but embedding that website inside an application and keeping that application always active...
Some point where I can start?
Sounds like you want to implement something like a Kioskmode. The Kioskmode is only available on Samsung devices.
On other devices you have to implement a Kiosk by yourself. But it is possible! There are some nice tutorials in the web. However you need to implement an application to get the user interactions.
First of all you need to activate the Kiosk after booting the device. You can use a Broadcast Reciever to get the Boot Event:
<receiver android:name=".BootReceiver">
<intent-filter >
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
You have to declare the permission in your manifest file:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
You can start your implementation in a class witch extends the BroadcastReciever. Start the activity from the actual android context.
public class BootReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Intent kioskIntent = new Intent(context, KioskMode.class);
kioskIntent .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(kioskIntent);
}
}
In the activity you can disable every button of the device, like back pressed, etc.
You can find a good tutorial for developing a kiosk under the following link, it shows how to disable power button, home button, back pressed,etc.:
http://www.andreas-schrade.de/2015/02/16/android-tutorial-how-to-create-a-kiosk-mode-in-android/
To disable the statusbar you just need to hide it with a theme:
android:theme="#android:style/Theme.Holo.NoActionBar.Fullscreen"
To display a HTML Page you can use a WebView. However in a webview is javascript and all errors disabled. So if you just want to show some information on the page your good with a WebView.
http://developer.android.com/reference/android/webkit/WebView.html
It is possible to use android for this type of scenario but only in Android 6.+
See Single use devices here for some information
I hope this is the information you are looking for.
In my Application I am not having any UI part, so I need to start a Service as soon as the Applicaton gets installed on the Device. I saw many links from which the answer was that its not possible but I guess it is surely possible. Just have a look at PlanB Application on the Android Market that does fulfil my requirement. Below is my Manifest file how I tried, but the Service was not called at all. So, let me know what is the best possible way to start a Service when the Application gets Installed.
UPDATE
I also tried using android.intent.action.PACKAGE_ADDED it works fine for detecting the Package for the other Applications but not for itself.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.auto.start"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="8" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<application
android:icon="#drawable/ic_launcher" >
<service android:name=".MyService">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</service>
<receiver android:name=".BootUpReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<category android:name="android.intent.category.DEFAULT"/>
<action android:name="android.intent.action.PACKAGE_INSTALL" />
<action android:name="android.intent.action.PACKAGE_ADDED" />
<data android:scheme="package"/>
</intent-filter>
</receiver>
</application>
</manifest>
Fortunately, Plan B does not work on Android 3.1+, as tested on a XOOM and a Galaxy Nexus.
What Plan B does is exploit a security hole that could be used by drive-by malware, which is specifically why Android prevents it from happening anymore.
UPDATE
To clarify: As inazaruk posted and I put into comments on other answers, all applications, upon installation, are placed in a "stopped" state. This is the same state that the application winds up in after the user force-stops the app from the Settings application. While in this "stopped" state, the application will not run for any reason, except by a manual launch of an activity. Notably, no BroadcastReceviers will be invoked, regardless of the event for which they have registered, until the user runs the app manually.
This block covers the Plan B scenario of remote-install-and-run, which they were taking advantage of previously. After all, with that, anyone with a hacked Google account would be at risk of having their device infected, hands-free as it were.
So, when the OP says:
I need to start a Service as soon as the Applicaton gets installed on the Device
the OP will be unsuccessful and will need to redesign the application to avoid this purported "need".
Applications installed on the /system partition are not subject to being placed into the "stopped" state after installation. If you have root, you can do,
$ adb root
$ adb remount
$ adb push your.apk /system/app
And it can immediately receive broadcast intents. This certainly doesn't provide a general purpose solution, but i wanted to mention it for completeness.
EDIT: Keep in mind that different versions of Android locate system APKs in different places. For example, Android 8 puts them under /system/app//.apk. Shell into your device and poke around and follow the same scheme used for other system APKs.
I agree with CommonsWare's answer to question: How to start android service on installation. In other words, you can't automatically start your service after you've just been installed.
One more thing about newer Android platforms: if you don't have UI at all, you'll have trouble starting your service even when using BOOT_COMPLETE intent on Android 3.1+.
That's because all installed applications are in stopped state. In this state applications will not receive ANY broadcast notifications.
In order to activate your application some other application (or user) needs to start your service or activity, or content provider. The usual workflow is when user clicks on your application's icon.
I've written a detailed explanations about this in my blog post.
Plan B does this launch by listening to the events which happen in the system. It uses a receiver which literally listenes to hundreds of events hoping that some of them will eventually fire up. So this is how you can do it. Otherwise, there are no built-in means to launch the application as soon as it gets installed.
I'm not sure what your constraints/purpose is, but if you can install another application that has an activity you can have it send an intent with the flag FLAG_INCLUDE_STOPPED_PACKAGES.
This will use your application for the intent resolution, even though it's in a stopped state. If the action of the intent matches one of your filters, it will also bring the package out of the stopped state.
I don't think so You can start service immediately after installed your application on device,
The application must first be invoked by the user through some sort of Activity.The only things you have to register some Broadcast Receiver with appropriate intents in manifest which invoke you service when something is happening on device but this remaing to Android 3.1 version.
EDIT:
After Android 3.1+ onwards you can not use any Broadcast for starting your application, because all application remains in inactive state after completion of device boot and to launch the application the user have to invoke it.(By touching the app icon).
As stated by CommonsWare in the answer to this question (which I suppose you have all ready seen, but chose to ignore) starting a Service on install is not possible - it is simply not a thing that is implemented into the platform.
Starting it automaticly at the next boot is however possible.
As stated in the Technical Details for PlanB:
Plan B will attempt to launch as soon as it downloads, but in some cases you will need to send an SMS to get it started.
My guess is that on a rooted phone you might be able to start the Service on install - but there's no guarantee that the phone is rooted, which is why PlanB will require recieving a text in some cases because that can be registered by the IntentFilter of the app and then used to start the Service.
there is an app on google play Android Lost which invoke the registration service for google push messages via an incoming sms without launching the app even once for version 3.0+.
Perhaps the best way to accomplish this (and now I'm speaking to the specific intent of the OP, a program that gets installed in order to retrieve a stolen phone, not the general question) is social engineering, not software engineering.
So, an icon with text like "Password List" or "My Bank Accounts" which suddenly appeared on the home screen would undoubtedly be clicked on. Look at the success of all sorts of other phishing, and here you would be targeting a thief, who's already motivated to continue nefarious activity. Let the thief start it for you. :)
HEY I think using a BroadcastRecivier to automatically start the app on restart of device hence it will automatically start on device start.Hope this will help