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.
Related
The device we’re speaking about is an Android 8 head unit with an external USB keyboard attached.
Well, I need to assign some tasks to this keyboard’s function keys, e.g. launching certain applications. Say, F4 can launch the media player, F5 the navigation app and so on. Either the Automate or the AutoInput Tasker plugin would be nice for this purpose, but all of this kind of applications use accessibility service for interacting with physical HID devices.
The big problem here is that this particular Android device regularly kills the accessibility services on (warm) reboot. Tried absolutely everything, from disabling power save mode to mark the Automate etc. as device admin app, nothing helped. So I have resigned and now I’m thinking for an alternative way to re-enable the appropriate accessibility service after the system disabled it after reboot for an unknown reason.
If the device was rooted I suppose there would be an easy way to restart an accessibility service by a shell command or whatever (just guessing, I’m pretty beginner in Android). But obviously I want to avoid rooting if possible. The ideal scenario would be to (auto)start a shell command / application / foreground service / whatever on each reboot – which would have enough administrative privileges to re-enable the accessibility service the system just have disabled during the reboot. Of course, all this stuffs without rooting the device. But I’m not really sure this can be done on Android (on Windows it would be enough a service running in System account, but Android is a different story).
A fair solution might be to
root the device,
install the shell command (application, foreground service, whatever) meant to restart the accessibility service after each reboot and
unroot the device (using SuperSU by example) in order to protect the user and not to void the warranty.
Would anybody tell me whether the above solution can give the desired result, and – if so – may I have some guidelines how to do this?
to achieve your purpose you should work with BroadcastReceiver and jobIntentService
first create a boot receiver
public class BootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
MyService.enqueueWork(context, new Intent());
}
}
}
add it to the manifest
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<receiver android:name=".BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
<service android:name=".MyService"
android:permission="android.permission.BIND_JOB_SERVICE"/>
Now you have to define your jobIntent
public class MyService extends JobIntentService {
public static final int JOB_ID = 0x01;
public static void enqueueWork(Context context, Intent work) {
enqueueWork(context, MyService.class, JOB_ID, work);
}
#Override
protected void onHandleWork(#NonNull Intent intent) {
// your code
}
}
And that’s it. This will directly start the service (when running on pre-O platforms) or enqueue work for it as a job (when running on O and later). No matter what the platform is, everything you pass in enqueueWork will ultimately appears in onHandleWork.
here is some useful links : link - link
I need to track install referrals for my android app. It's working fine in most of the devices. But in Redmi device, the broadcast is not getting triggered. I tested it with Redmi Note 4
I have tested it both from via ADB as well as play store. Both don't trigger the broadcast in Redmi device
Below is the code that I am using
public class ReferrerReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("Broadcast", "RECEIVED!");
}
}
<receiver
android:name=".receiver.ReferrerReceiver"
android:exported="true">
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER"/>
</intent-filter>
</receiver>
Please suggest if someone faced the same issue and got some solution??
Is your app in the list of "protected apps" that are allowed to run in the background? If not, it won't get automatically started. This is a problem on devices like Xiaomi, Huawei and others. There should be a settings page in "Settings->Apps-Security" that allows you to add your app to a list of apps that are allowed to autostart, run in the background, etc. Each device manufacturer does this a bit differently, but in general we see this on Chinese devices as a way to preserve battery life.
See also:
How to get MIUI Security app auto start permission programmatically?
How to enable AutoStart option for my App in Xiaomi phone Security App programmatically in android
GCM push notifications for android devices are not working on MI and Letv mobiles
In Redmi device some android applications needs permissions. Please allow the permissions manually in the device. By using app permissions option in your device give all permissions. It may work which i had observed for my app.
There is always some issues with the miui due to their restrictions on background processes you can turn them on here is how it goes
1: Go to settings --> manage apps' battery usage --> choose apps. From there, pick all the apps you want to receive push notifications and select "No restrictions."
2: Go to settings --> permissions --> autostart. From there, pick the apps you want, and toggle the switch to turn it on.
3: Lock the app in the "recent apps"/ "app overview" plane. Do so by first opening the apps, then press the "recent apps/overview button" (that's the square button on stock Android, or the button with three horizontal lines on the Mi Mix). From there, find the app you want to receive notifications, pull down on it to "lock it", so it never gets cleared.
4: This last step requires Developer Options privileges. To enable that, go to settings (man... I'm getting tired of typing "go to settings" ...) --> about phone
tap on MIUI version tab like eight times. You should then get a little message saying "you are now a developer." Then head back out to settings, go to developer option, scroll to nearly the bottom, find "memory optimization," and turn it off.
Again, maybe step 4 is all you need.
I use Redmi 3 Pro and always have trouble with Android Permission. Xiaomi devices use custom ROM that caused permission request buggy sometimes.
The overlay service permission is always forced set to Denied in every app that I installed. I must manually Allow it.
Nice workaround I found to let Xiaomi devices auto start permission: How to get MIUI Security app auto start permission programmatically?
You could solve this issue by using the Play Install Referrer Library api 1.0 from Google. I did it this way and it works fine on devices that block the auto start by default.
First Add the following line to the dependencies section of the build.gradle file for your app:
dependencies {
...
compile 'com.android.installreferrer:installreferrer:1.0'
}
Then you should implement the interface InstallReferrerStateListener and its methods onInstallReferrerSetupFinished and onInstallReferrerServiceDisconnected in your Activity
Call the newBuilder() method to create an instance of InstallReferrerClient class.
Call the startConnection() to establish a connection to Google Play.
The startConnection() method is asynchronous, so you must override InstallReferrerStateListener to receive a callback after startConnection() completes.
You should also Override the onInstallReferrerSetupFinished() method to handle lost connections to Google Play. For example, the Play Install Referrer Library client may lose connection if the Play Store service is updating in the background. The library client must call the startConnection() method to restart the connection before making further requests.
Example:
InstallReferrerClient mReferrerClient
mReferrerClient = InstallReferrerClient.newBuilder(this).build();
mReferrerClient.startConnection(new InstallReferrerStateListener() {
#Override
public void onInstallReferrerSetupFinished(int responseCode) {
switch (responseCode) {
case InstallReferrerResponse.OK:
// Connection established
break;
case InstallReferrerResponse.FEATURE_NOT_SUPPORTED:
// API not available on the current Play Store app
break;
case InstallReferrerResponse.SERVICE_UNAVAILABLE:
// Connection could not be established
break;
}
}
#Override
public void onInstallReferrerServiceDisconnected() {
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
}
});
After you have established a connection to the Play Store app:
Use the synchronized getInstallReferrer() method to return ReferrerDetails.
Then, use methods in ReferrerDetails to get install timestamps and a referrer url.
ReferrerDetails response = mReferrerClient.getInstallReferrer();
response.getInstallReferrer();
response.getReferrerClickTimestampSeconds();
response.getInstallBeginTimestampSeconds();
For further info:
https://developer.android.com/google/play/installreferrer/library
Hope this helps!!
Android API level 24 introduces a new Service called the CallScreeningService. The documentation says that the service can by implemented by the default dialer to screen incoming calls. I would like to implement this service in my own app, preferably without creating an entire dialer app, but a simple naive implementation seems to be ignored by the OS when an incoming call happens.
AndroidManifest.xml snippet:
<service android:name="com.example.callbouncer.CallService" android:permission="android.permission.BIND_SCREENING_SERVICE">
<intent-filter>
<action android:name="android.telecom.CallScreeningService"/>
</intent-filter>
</service>
CallService.java:
// imports...
public class CallService extends CallScreeningService {
#Override
public void onScreenCall(Call.Details callDetails) {
CallResponse.Builder response = new CallResponse.Builder();
Log.e("CallBouncer", "Call screening service triggered");
respondToCall(callDetails, response.build() );
}
}
There are no errors while building or installing this program, but the screening doesn't seem to be taking place. Have I done something wrong (like the manifest or missing implementations/overrides in the service) or is it just not possible? If it's not possible in a small app like this, will it be possible if I implement an entire dialing app and set it as the default dialer? Finally, if that's the case, is there anything preventing me from just forking the dialer out of the AOSP and adding my features to it?
As of Android 10 (API 29+), you can have a CallScreeningService without the requirement of also implementing an entire dialer app. Until Android 10, only the default dialer app's call CallScreeningService would be invoked.
https://developer.android.com/about/versions/10/features#call-screening
Don't get too excited though, because it's very buggy and does not work as the documentation says it does:
CallScreeningService#onScreenCall is called for known contacts
CallScreeningService#setSkipCallLog doesn't show blocked calls in the call log
My workaround for getting called for known contacts was to ask the user for contact access and check if the incoming caller was in the user's contacts. There is no workaround for the other issues at the moment.
I made a very basic screening app that declines all calls from numbers not in the user's contacts you can use an an example if you like: https://github.com/joshfriend/gofccyourself
Looking at the docs you linked to:
This service can be implemented by the default dialer (see
getDefaultDialerPackage()) to allow or disallow incoming calls before
they are shown to a user.
Don't think you can do this in a separate app (at least with the current interface: I'd expect in the not too distant feature it will be exposed).
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.
I am implementing a login system for an Android application utilizing the built-in accounts system (with the AccountManager APIs).
All is well and good on Android 2.2+, but on Android 2.1 not including a SyncAdapter causes reboots in the account settings screen (see http://code.google.com/p/android/issues/detail?id=5009 and AccountManager without a SyncAdapter?)
To get around this I implemented a stub SyncAdapter, which just returns null from IBinder onBind(Intent intent), and added the relevant stuff to the manifest. This resolves the reboot issue on Android 2.1.
However it introduces a further problem: after an account is added the Android system will, sometime later, initiate an account sync. Although no errors occur (indeed my SyncAdapter does nothing, it has no way to cause errors unless by returning null), the sync icon stays stuck in the notification bar at the top. This results in the Android sync system maintaining a permanent wake-lock, preventing the device from sleeping.
The account does not list any syncable components in the account settings screen (under the 'Data and synchronization' header), and always displays 'Sync is off' for the sync status in the list of accounts (even while the sync icon is visible in the notifications bar). Disabling account syncing does not remove the problem. Removing the account stops the problem.
My guess is I should not be returning null. Should I be returning a basic implementation of ThreadedSyncAdapter? Any help getting an account system without an associated sync working properly on 2.1 and 2.2+ is much appreciated.
Since this is the only question I've seen related to this problem, here's a >year late answer. I also came across the permanent wake-lock problem due to the android system syncing my custom account automatically.
The best way to handle this, which requires minimum code and actually makes it so the account never syncs unless specifically called to sync in code:
ContentResolver.setIsSyncable(account, ContactsContract.AUTHORITY, 0);
Now this requires that the moment you create your account you call this static method. Whereas the first parameter being the account to set this setting for, the second parameter being the used contentprovider's authority, and the third being the integer that when set to a positive number enables syncing, when set to 0 disables syncing and when set to anything else makes it unknown. The authority to use can be found inside your "sync_something.xml" under the contentAuthority attribute, which is used by your SyncAdapter :
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
android:contentAuthority="com.android.contacts"
android:accountType="com.myapp.account"/> <!-- This being your own account type-->
The above xml file is specified inside the service part of your AndroidManifest.xml:
<service android:name=".DummySyncAdapterService"
exported="true"
android:process=":contacts">
<intent-filter>
<action android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data android:name="android.content.SyncAdapter"
android:resource="#xml/sync_something" /> <!--This points to your SyncAdapter XML-->
</service>
This is the code snippet I use to create my custom account inside my LoginActivity:
Account account = new Account("John Doe", "com.myapp.account");
ContentResolver.setIsSyncable(account, ContactsContract.AUTHORITY, 0);
AccountManager am = AccountManager.get(LoginActivity.this);
boolean accountCreated = am.addAccountExplicitly(account, "Password", null);
Bundle extras = LoginActivity.this.getIntent().getExtras();
if(extras != null){
if (accountCreated) {
AccountAuthenticatorResponse response = extras.getParcelable(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE);
Bundle result = new Bundle();
result.putString(AccountManager.KEY_ACCOUNT_NAME, "John Doe");
result.putString(AccountManager.KEY_ACCOUNT_TYPE, "com.myapp.account");
response.onResult(result);
}
}
The great part of this is that when the system tries to sync the service, it checks if the service is syncable first, if it is set to false it cancels the syncing. Now you don't have to create your own ContentProvider nor does your ContentProvider get shown under Data and Synchronization. However you do need to have a stub implementation of AbstractThreadedSyncAdapter which returns an IBinder inside it's onBind method. And last but not least it makes it so that an user can't enable syncing or use the "Sync Now" button for this account unless you've added the functionality inside your app.
I sort of solved my own problem: you cannot return null from the onBind method of your service - you must return the IBinder of an AbstractThreadedSyncAdapter.
This has the undesired effect of adding an entry into the Data and Synchronization section of the account settings page, even though my implementation of AbstractThreadedSyncAdapter does nothing; I was hoping to avoid this.
To summarize, in order to make use of the accounts system in Android you must:
Implement a service that has an IntentFilter for android.content.SyncAdapter.
This service must return the IBinder of an AbstractThreadedSyncAdapter implementation from it's onBind method.
This then necessitates that you have a ContentProvider (can just be a stub implementation) that is referred to as the contentAuthority in your SyncAdapter XML file.
This has the down-side that your ContentProvider is listed under the Data and Synchronization header on your account settings page.