Create an automatic launch-able Broadcast Receiver in Android - java

Problem:
I am willing to create an application that simply starts as a background process and whenever a new message comes into the device it should log it into a file or simply display a toast message.
I have read a lot of blogs and tried to follow the steps as mentioned. But, I keep on sending messages on my device and nothing displayed not even in device log. I want to run it on devices from Froyo to Lollipop. So, I am not willing to use new Telephony API which supports API 19 and later versions.
Manifest File
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.abc.test"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="15" />
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<receiver android:name=".SMSHandler">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
</application>
</manifest>
Source File
package com.abc.test;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class SMSHandler extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
Toast toast = Toast.makeText(context, "message initiated",
Toast.LENGTH_LONG);
toast.show();
if (intent.getAction()
.equals("android.provider.Telephony.SMS_RECEIVED")) {
toast = Toast.makeText(context, "message received",
Toast.LENGTH_LONG);
toast.show();
}
}
}
Environment:
IDE:
Android Studio
Min SDK Version:
8
Tested On:
ICS Device (Sony Xperia U)
Kit-Kat (MOTO G)

You need to add an activity, then run that activity, before this BroadcastReceiver will work.
More accurately, something needs to use an explicit Intent before your app will be moved out of the stopped state and allow manifest-registered BroadcastReceivers to work. The simplest way to do that is to have a launcher activity, and run that activity from the launcher.
To learn more, see "Launch controls on stopped applications" in the Android 3.1 release notes, along with this blog post.

Your Code look like this in manifest file
<receiver android:name=".SMSHandler"
android:exported="true"
android:enabled="true">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
Add the following to your<receiver> in the manifest:
android:enabled="true"
android:exported="true">
Furthermore, according to this thread, it seems that you have to manually start one of your activities before the broadcast receiver will start working, i.e. the application has to have been launched at least once before any broadcast receiver will work.

Related

Broadcast Reciever, ¿Am I doing it right?

first question here...
I have this practice from my college, but the course sometimes doesn't explain everything, and it's about broadcast and receiving a Toast message.
(Some things are going to be in Spanish)
You see, the first app it's about having a view with a button:
Activity View
The only thing that it does is sending a message through a button, and the OnClick has linked this method that is on the Activity, which name is Emisora.java (there is no main activity, but it is configured to this be the launch activity):
public void Emision(View v){
Intent intent = new Intent();
intent.setAction("com.tecmilenio.practica91");
intent.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
sendBroadcast(intent);
}
The Manifest is:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tecmilenio.practica91">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".Emisora">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
Then I have the other app, which doesn't have an activity but it does have an Broadcast Reciever:
package com.tecmilenio.receptor;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class BroadcastReceptor extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Transmission Recieved", Toast.LENGTH_SHORT).show();
}
}
(I know having a Toast for this is not the best practice but is just for the practice of the course)
And its Manifest is:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tecmilenio.receptor">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<receiver
android:name=".BroadcastReceptor"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.tecmilenio.practica91"/>
</intent-filter>
</receiver>
</application>
</manifest>
And when I install and execute the first one it just doesn't happen anything, I tap the button but nothing happens.
Then I later saw that in the second project (the receiver) when I execute it from the Android Studio, the app doesn't appear in the phone, neither execute anything, but i thought this was normal due to the lack of an activity in it. Then I also saw that when executing through the studio also the Run console sends me the message "Timed out waiting for process (com.tecmilenio.receptor) to appear on xiaomi-mi_8-2ef63c6e.", maybe this has something to be (?)
I would appreciate that someone explains me this... Thanks!
Update
I have found that the problem has to be a lot with the Timeout on launch, adding an activity with nothing and launching that activity makes it work, however that is not what it's supposed to do, it is supposed that it shouldn't have any activity, and should execute the OnRecieve when the "practica91" app sends the message...
Is there any way of how to do this?
Set action declared in manifest and sending broadcast from an activity is different.
try using the same action at both the places -
Intent intent = new Intent();
intent.setAction("com.tecmilenio.practica91");
intent.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
sendBroadcast(intent);
I think there is a small mistake here. You're sending as an action in the first app
the following string com.tecmilenio.emision. Whereas in the second app you're registering the broadcast's action as below
<action android:name="com.tecmilenio.practica91"/>
The first change would be to rename the broadcast action to com.tecmilenio.emision.
<receiver
android:name=".BroadcastReceptor"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.tecmilenio.emision"/>
</intent-filter>
</receiver>
Another important point is that when sending the broadcast add FLAG_INCLUDE_STOPPED_PACKAGES flag to the intent because when you broadcast from app A to app B , app B might not be running, this flag insures that the broadcast reaches out even apps not running:
Regards I'm Mexican too!

I am trying to build an app, that creates a notification when wifi state is changed

I am building an app that sends a notification when wifi connection is established. Since I am using android 9 setting intent filter in AndroidManifest.xml doesn't work.
I created a custom BroadcastReceiver, that creates a notification, and it works if I register receiver in onCreate.
Here is the registerReceiver part of the code in onCreate (it works when app is opened)
receiver = new WifiStateReceiver();
IntentFilter filter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
registerReceiver(receiver, filter);
Here is my BroadcastReceiver:
public class WifiStateReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.i("TEST", "IT WORKS!");
}
}
And here is my AndroidManifest.xml
.
.
.
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
.
.
.
<receiver
android:name=".WifiStateReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.net.wifi.STATE_CHANGE"/>
</intent-filter>
</receiver>
.
.
.
After I close my app this doesn't work anymore. So I need some kind of service that never closes, but I'm not sure how battery inefficient this method is. Is there a way to run a service when wifi connection/state changes? And as I already said, putting intent-filter in AndroidManifest doesn't seem to work as I am using android 9.

Debug app that runs at boot

I am using Android Studio.
I added a BroadcastReceiver for my app that receives android.intent.action.BOOT_COMPLETED, the receiver just shows up a Toast for testing. The problem is I get "App has stopped" message just after Android starts up.
My first question is: is there anyway to debug that at startup and see where is the problem by myself? Because I can't see any log referring to that problem in Android Studio.
My second question is related to the problem itself. Here is the code:
XML:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="myapp">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name="MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name=".AutoStartReceiver"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
</manifest>
Java: BroadcastReceiver
public class AutoStartReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "loaded", Toast.LENGTH_LONG).show();
throw new UnsupportedOperationException("Not yet implemented");
}
}
The third question is: Is it OK to do some heavy work (read some files and set the AlarmManager) in the receiver rather than creating a service? because as of API 26 Android is putting a lot of restriction to services.
Thank you
For the debugging part I used this (in the Terminal, when the emulator is on) :
adb shell am set-debug-app -w --persistent <your.app.package>
to start debugging, then click Attach debugger to android process when the app prompts for it on the emulator.
To disable this:
adb shell am clear-debug-app <your.app.package>
Found answer here : https://medium.com/#elye.project/debug-app-deeplink-at-launch-time-bdb2cf04a9e6
Apps that launch on boot can be debugged the second your device gets a debugging connection, which usually happens just before the app itself would boot. Just open logcat and watch for the device and app to pop up after reboot. Note that this assumes the app is debuggable. Apps that aren't will simply not show any logs.
You get the MyApp has unfortunately stopped message for the obvious reason of this code:
public class AutoStartReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "loaded", Toast.LENGTH_LONG).show();
throw new UnsupportedOperationException("Not yet implemented");
}
}
You throw an exception, meaning it'll stop.
As for what you do in the service, as long as it uses within a reasonable amount of RAM and processor (extremely heavy services are more likely to be killed to save battery and memory) you're good to go

Android notification is not showing it's content when app is not running

Here is my interesting problem. Android notification that comes from GCM is not showing title and content (just shows App Name, and when click, open the MainActivity) when app is not running.
But when the app is open, it's showing successfully title and content. What can be the problem? It was running without problem and I didn't change anything.
Manifest:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="com.package.xxx.permission.C2D_MESSAGE" />
<permission android:name="com.package.xxx.permission.C2D_MESSAGE" android:protectionLevel="signature" />
<receiver
android:name="com.google.android.gms.gcm.GcmReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.package.xxx" />
</intent-filter>
</receiver>
<service
android:name=".Service.GcmService"
android:exported="false" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
GcmService.java:
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
import android.text.TextUtils;
import android.util.Log;
import com.google.android.gms.gcm.GcmListenerService;
import com.package.xxx.Activity.ReadNormal;
import com.package.xxx.R;
public class GcmService extends GcmListenerService {
public GcmService() {
}
#Override
public void onMessageReceived(String from, Bundle data) {
Log.d("GCMService", data.toString());
String type = data.getString("type", "");
if(type.equals("news")) {
showNewsNotification(data);
}
}
private void showNewsNotification(Bundle data) {
String neId = data.getString("neId");
if(TextUtils.isEmpty(neId)) {
return;
}
int id = Integer.valueOf(neId);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
.setContentTitle(data.getString("neTi"))
.setContentText("Click to read more.")
.setSmallIcon(R.drawable.ic_launcher)
.setAutoCancel(true);
Intent i = new Intent();
i.putExtra("neSi", data.getString("neSi"));
i.putExtra("neUr", data.getString("neUr"));
i.putExtra("neTi", data.getString("neTi"));
i.putExtra("neIm", data.getString("neIm"));
i.putExtra("neId", id);
i.setClass(this, ReadNormal.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
/***/
PendingIntent pi = PendingIntent.getActivity(getApplicationContext(), 0, i, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(pi);
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(0, mBuilder.build());
}
#Override
public void onDeletedMessages() {
}
#Override
public void onMessageSent(String msgId) {
}
#Override
public void onSendError(String msgId, String error) {
}
Thank you.
Logs when app is running.
D/GCMService: Bundle[{neId=4663755, neIm=http://icdn.posta.com.tr/editor/HD/30/1/2016/fft2mm7549077.jpg, neSi=Posta, neTi=Erdoğan: Rusya sonucuna katlanır, neUr=http://www.posta.com.tr/turkiye/HaberDetay/Erdogan--Rusya-sonucuna-katlanir.htm?ArticleID=324647, type=news, notification=Bundle[{e=1}], collapse_key=com.tekmobil.guncelhaber}]
Logs when app is NOT running.
(empty, there is no log)
Found the problem. I was using 8.4.0 version (up-to-date) of play services.
compile 'com.google.android.gms:play-services-gcm:8.4.0' //GCM
I reduced the version to 8.3.0. It works as expected.
Instead of
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(0, mBuilder.build());
try using
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
notificationManager.notify(0, mBuilder.build());
In brief: try setting content_available=false when building the push on server side. The explanation follows.
This happens from version 8.4.0 of play services.
The documentation says that if you send a downstream message with both data and notification payload, the behavior changes if the App is in foreground or in background:
in foreground the listener onMessageReceived is called and you can manually handle your notification
in background the notification is automatically built by the system by taking title and body from the notification payload. If you don't specify them, the title is filled with application name and the body is left empty (and that's seems your case).
In your case I saw, in the message bundle, this strange thing notification=Bundle[{e=1}]
I encountered the same problem. This notification payload is self generated. I managed to remove it by setting content_available=false when building the push on server side. This is a problem if you are also working with iOS, but I didn't find any better solution...try it out.
Here the google doc I cited: https://developers.google.com/cloud-messaging/concept-options#notifications_and_data_messages
Hope it helps, bye
I think your issue is in this line:
you have not included this:
<service
android:name="com.example.MyInstanceIDListenerService"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.gms.iid.InstanceID" />
</intent-filter>
</service>
Lollipop changes this slightly by creating a small pop up at the top of the device window when a Notification is created.
Here's a Official documentation: setFullScreenIntent
Using this method, you can create a new Activity with any custom layout you want and launch that instead of placing the Notification in the status bar.
The problem is with the GCM 8.4.0 version, it is sending a notification payload even if you don't send it in your server.
notification=Bundle[{e=1}
But if you add this e field with value zero in your server it will work.
For more details se my answer here.

Broadcast Receiver not receiving BOOT and MEDIA_MOUNTED intent

I'm trying to create a simple BroadcastReceiver that can receive the android.intent.action.BOOT_COMPLETED intent as well as the android.intent.action.MEDIA_MOUNTED intent. The idea is to start a service on receiving either of these intents. Thus the service should be started after Android boot is complete or when an USB storage device is connected to the Android target(if the service is not already started by then).
Permissions used by the application are defined in this section
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
The following section defines the BroadcastReceiver responsible for handling the intents and starting the corresponding service.
<receiver
android:name="com.example.systemupgradeapplication.IntentReceiver"
android:label="USB Detection Receiver"
android:enabled="true"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED" >
<intent-filter>
<action android:name="android.intent.action.MEDIA_REMOVED" />
<action android:name="android.intent.action.MEDIA_EJECT" />
<action android:name="android.intent.action.MEDIA_BAD_REMOVAL" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MEDIA_MOUNTED" />
<data android:scheme="file" />
</intent-filter>
<intent-filter android:priority="999" >
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
The corresponding service that should be started from the Broadcast Receiver is defined in the following section
<service android:name=".SysUpgradeService" />
Note: The receiver and service components are defined within the <application> section of the Android Manifest.
The following snippet is the Class responsible for handling the intents broadcasted
public class IntentReceiver extends BroadcastReceiver {
private final static String TAG = "IntentReceiver";
private static boolean m_UsbInserted = false;
private static boolean m_UsbRemoved = true;
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "LaunchReceiver::ACTION_MEDIA_MOUNTED :: intent received with path= ");
// TODO Auto-generated method stub
//if(intent.)
String action = intent.getAction();
if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
String path = intent.getDataString();
if(path.contains("usb")) {
m_UsbInserted = true;
Log.d(TAG, "LaunchReceiver::ACTION_MEDIA_MOUNTED :: intent received with path= "+path);
Intent myIntent = new Intent(context, SysUpgradeService.class);
myIntent.putExtra("path", path);
context.startService(myIntent);
}
}else if(action.equals(Intent.ACTION_BOOT_COMPLETED)) {
Log.d(TAG, "BOOT Completed intent received");
context.startService(new Intent(context, SysUpgradeService.class));
}
The problem I am facing is that none of the intents are arriving at my broadcast receiver(None of the Logs in the IntentReceiver class are being printed in logcat) even though I can see in the Android Debug logs that the BOOT_COMPLETE and MEDIA_MOUNTED intents are being broadcast. Also This application is not starting after android system is booting up.
I appreciate your help in this regard, what may be wrong with my approach and some possible solutions.
Okay, so I pushed the apk to /system/priv-app which is where System Applications which are part of custom ROM are placed. Now I do not need any activity in my application since it is part of the custom ROM and is recognized as a system application. It seems that if your application is a 3rd party application it must have an activity to be able to receive broadcasted intents.
However in this case I have control over the custom ROM source code as well as root access on the device. So both the approaches work
Make your application part of the custom ROM source, build and flash on device.
Get root access on device, push your apk to /system/priv-app (4.4 onwards), reboot and voila!
Make Sure you have atleat one activity present in your Application.From Android 3.1, BroadcastReceiver will not work until the user has manually launched an activity, This is for provide security . once the user runs the app for the first time then your BroadcastReceiver will run always except it does not Force Stop it. Once activity launch at first time your broadcast receiver will run even after reboot your deice.

Categories