Android use Broadcast Receivers to send value - java

I have this AccessibilityService class:
public class USSDService extends AccessibilityService {
public static String TAG = "USSDService";
public String responsee="";
#Override
public void onAccessibilityEvent(AccessibilityEvent event) {
Log.d(TAG, "onAccessibilityEvent");
String text = event.getText().toString();
if (event.getClassName().equals("android.app.AlertDialog")) {
performGlobalAction(GLOBAL_ACTION_BACK);
Log.d(TAG, text);
Intent intent = new Intent("message");
intent.putExtra("value", text);
Toast.makeText (this,text,Toast.LENGTH_LONG).show();
this.sendBroadcast(intent);// write a broad cast receiver and call sendbroadcast() from here, if you want to parse the message for balance, date
}
}
#Override
public void onInterrupt() {
}
#Override
protected void onServiceConnected() {
super.onServiceConnected();
Log.d(TAG, "onServiceConnected");
AccessibilityServiceInfo info = new AccessibilityServiceInfo();
info.flags = AccessibilityServiceInfo.DEFAULT;
info.packageNames = new String[]{"com.android.phone"};
info.eventTypes = AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
info.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
setServiceInfo(info);
}}
As you can see in the method onAccessibilityEvent, I send intent by using the method sendBroadcast.
In MainActivity I use BroadcastReceiver to receive the value like this:
public class MainActivity extends AppCompatActivity {
private BroadcastReceiver bReceiver = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent) {
//put here whaterver you want your activity to do with the intent received
Log.i("onReceive",intent.getStringExtra("value") );
}
};
protected void onResume(){
super.onResume();
Log.i("onResume", "22222");
LocalBroadcastManager.getInstance(this).registerReceiver(bReceiver, new IntentFilter("message"));
}
protected void onPause (){
super.onPause();
Log.i("onPause", "11111");
LocalBroadcastManager.getInstance(this).unregisterReceiver(bReceiver);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);}}
My App works fine when I call ussd the method onAccessibilityEvent is work and the value show in Toast, but the method onReceive did not work and I don't know where the problem is. Please help me.

An AccessibilityService that has been launched properly and your Activity are going to exist in separate processes. This is by definition. Assuming that you have launched your AccessibilityService properly, the following is what you want.
public class USSDService extends AccessibilityService {
public void onAccessibilityEvent(AccessibilityEvent event) {
Intent intent = new Intent(getPackageName() + "ACTION_ID");
intent.putExtra("extra_id", "value");
sendBroadcast(intent);
}
}
You would then register for this broadcast in your Activity like so:
public class MainActivity extends AppCompatActivity {
protected void onResume(){
super.onResume();
registerReceiver(new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("Broadcast", intent.getExtras().getString("extra_id"));
}
}, new IntentFilter(getPackageName() + "ACTION_ID"));
}
}
Important part here is A: your intent filter is tied to your package name, and that "ACTION_ID" is always the same string. Ultimately this is probably best accomplished by a public static final string in either your Activity class or your service class... or in some other class abstracting away this layer of communication.

Related

Why does the UI stop updating countdown after restarting the app while using intent service?

I am trying to show a countdown in a textview from a loop inside an Intent Service. I am using the result receiver class for the communication between Intent Service and Activity. It works fine when I start the service for the first time. The textview shows the countdown for each time the loop runs in the service.
But when I close and launch the app again the textview doesn't show the countdown and only shows the hard coded text, while on the other hand the service stills runs in the background.
Here is my code snippet for the MainActivity
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
public static final String RECEIVER_INTENT_EXTRA_NAME = "message_receiver_intent_extra";
private static final String TAG = "MainActivity";
private Intent intent;
MyIntentService myIntentService;
public TextView serviceCountdown;
private Button startButton, stopButton;
private Handler handler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getSupportActionBar().hide();
myIntentService = new MyIntentService();
startButton = findViewById(R.id.startServiceButton);
stopButton = findViewById(R.id.stopServiceButton);
startButton.setOnClickListener(this);
stopButton.setOnClickListener(this);
handler = new Handler();
serviceCountdown = findViewById(R.id.serviceCountdown);
MessageReceiver messageReceiver = new MessageReceiver(handler);
// send intent service
intent = new Intent(this, MyIntentService.class);
intent.putExtra(RECEIVER_INTENT_EXTRA_NAME, messageReceiver);
}
#Override
public void onClick(View v) {
if (startButton.equals(v)) {
ContextCompat.startForegroundService(getApplicationContext(), intent);
}
if (stopButton.equals(v)){
stopService(intent);
}
}
public class MessageReceiver extends ResultReceiver {
public MessageReceiver(Handler handler) {
super(handler);
}
#Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
super.onReceiveResult(resultCode, resultData);
if (resultCode == 1 && resultData != null){
final String countdown = resultData.getString("countdown");
handler.post(new Runnable() {
#Override
public void run() {
serviceCountdown.setText(countdown);
}
});
}
}
}
}
And here is my code for the Intent Service Class
public class MyIntentService extends IntentService {
private static final String CHANNEL_ID = "my_channel_id";
private static final String TAG = "MyIntentService";
public MyIntentService() {
super("MyIntentService");
setIntentRedelivery(true);
}
#Override
public void onCreate() {
super.onCreate();
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent,0);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("My Service Title")
.setContentText("This is sample notification text")
.setSmallIcon(R.drawable.ic_battery)
.setContentIntent(pendingIntent)
.build();
startForeground(1, notification);
}
#Override
protected void onHandleIntent(#Nullable Intent intent) {
ResultReceiver resultReceiver = intent.getParcelableExtra(MainActivity.RECEIVER_INTENT_EXTRA_NAME);
Log.d(TAG, "onHandleIntent: called");
synchronized (this) {
for (int i = 10; i >= 0; i--) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.d(TAG, "Service is looping : " + i);
Bundle bundle = new Bundle();
bundle.putString("countdown", String.valueOf(i));
resultReceiver.send(1, bundle);
}
}
}
#Override
public void onDestroy() {
Log.d(TAG, "onDestroy: called");
super.onDestroy();
}
}
In the real project, my intention is not to using the loop to show a countdown. It is just for testing and debugging purpose.
Use Local Broadcast Receiver from your service to activity. Now you getting the ResultReceiver from the MainActivity Intent. When the activity destroyed intents are also destroyed.
Use this Broadcast Receiver code in your service class.
LocalBroadcastManager localBroadcastManager =
LocalBroadcastManager.getInstance(this);
Intent sendIntent = new Intent(INTENT_ACTION_KEY);
sendIntent.putExtra(DATA_KEY, data);
localBroadcastManager.sendBroadcast(sendIntent);
Get this local broadcast receiver in your activity.
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent != null) {
//Perform your logic.
}
}
};
Make sure you register this broadcast when activity starts and unregister it when stop.
#Override
public void onStart() {
super.onStart();
LocalBroadcastManager.getInstance(this).registerReceiver((broadcastReceiver),
new IntentFilter(INTENT_ACTION_KEY));
}
#Override
public void onStop() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver);
super.onStop();
}

onResume() and onPause() is being called on the first launch

I am having an activity and on Launching the activity through Intent from one of my service, onCreate(), onPause() and onResume() is called.
I am not very sure where i am doing wrong, i have removed all the code, just the basic function codes are available, and also i have removed all the codes which were opening that particular activity, still the behaviour is same.
I am including the simplest code i am using
ActivityClass.java
public class ActivityClass extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
System.out.println("TEST : onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_lockscreen);
ButterKnife.bind(this);
}
#Override
protected void onPause() {
System.out.println("TEST : onPause");
super.onPause();
}
#Override
protected void onDestroy() {
System.out.println("TEST : onDestroy");
super.onDestroy();
}
}
Service class
public class OverlayService extends Service {
Context context;
public static final String TAG = OverlayService.class.getSimpleName();
public OverlayService(Context applicationContext) {
super();
context = applicationContext;
}
public OverlayService() {
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "[onCreateService]");
super.onStartCommand(intent, flags, startId);
KeyguardManager myKM = (KeyguardManager) getApplicationContext().getSystemService(Context.KEYGUARD_SERVICE);
if(myKM.inKeyguardRestrictedInputMode()) {
//it is locked
showOverlayActivity();
} else {
//it is not locked
}
registerOverlayReceiver();
context = this;
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
unregisterOverlayReceiver();
Log.i("EXIT", "ondestroy!");
}
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
Intent broadcastIntent = new Intent("ac.in.ActivityRecognition.RestartSensor");
sendBroadcast(broadcastIntent);
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void unregisterOverlayReceiver() {
if (overlayReceiver != null) {
unregisterReceiver(overlayReceiver);
}
}
private static final String ACTION_DEBUG = "kunal.lockoverlay.action.DEBUG";
private void registerOverlayReceiver() {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(ACTION_DEBUG);
registerReceiver(overlayReceiver, filter);
}
private BroadcastReceiver overlayReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.d(TAG, "[onReceive]" + action);
if (action.equals(Intent.ACTION_SCREEN_ON)) {
// ACTON_SCREEN_ON
showOverlayActivity();
} else if (action.equals(ACTION_DEBUG)) {
showOverlayActivity();
}
}
};
private void showOverlayActivity() {
Intent intent = new Intent();
intent.setClass(this, ActivityClass.class);
intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
Can someone point some of the possible reasons for this behaviour or could identify where i am doing wrong?
Well everything will be called regardless, you have defined it in your ClassName.java file.
You override the method and define it in your class to perform certain action/function when that is called.
For eg.,
You could use onResume to clear an arraylist and add updated elements to arraylist (OR) dismiss all notifications from your app on moving to that activity, say
#Override
public void onResume() {
super.onResume();
calendarList.clear();
//dismiss all notifications here
NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager!=null)
notificationManager.cancelAll();
}
OR eg., onDestroy to destroy the bluetooth service,
#Override
public void onDestroy() {
super.onDestroy();
if (mBluetoothService != null) {
mBluetoothService.stop();
}
}
Hope that clarifies. Happy coding!
About service class, you should call registerReceiver() or initialize variables in onCreate instead of onStartCommand because onCreate is only called once at the first time of starting service and onStartCommand will be called every time you want to trigger an action to the service by calling startService(Intent).

broadcast Intent / receiver

In my Application I have a Broadcast receiver (registered in manifest) class from which I want to send an Intent to MainActivity. Therefore I have another broadcast receiver (dynamically registered) in MainActivity and an Intent Filter. But I don't receive the Intent in Main Activity.
This is the code:
public class SmsReceiver extends BroadcastReceiver {
public static final String SMS_BUNDLE = "pdus";
public SmsReceiver(){
}
String TAG = SmsReceiver.class.getSimpleName();
#Override
public void onReceive(Context context, Intent intent){
Bundle bundle = intent.getExtras();
if (bundle != null) {
Object[] sms = (Object[]) bundle.get(SMS_BUNDLE);
String str = "";
for (int i=0; i < sms.length; i++) {
SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) sms[i]);
String smsbody = smsMessage.getMessageBody().toString();
str += smsbody;
}
Intent bcIntent = new Intent();
bcIntent.setAction("SMS_RECEIVED_ACTION");
bcIntent.addCategory(Intent.CATEGORY_DEFAULT);
bcIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
bcIntent.putExtra("message", str);
context.sendBroadcast(bcIntent);
}
}
}
and in the MainActivity:
public class MainActivity extends AppCompatActivity
{
public boolean receivedSMS;
public String displaySMS;
private BroadcastReceiver iReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String qqq = intent.getExtras().getString("message");
info2(intent.getExtras().getString("message"));
evalMsg(qqq);
}
};
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
graphInit();
timerInit();
smnInit();
}
#Override
protected void onResume(){
super.onResume();
IntentFilter iFilter = new IntentFilter();
iFilter.addAction("SMS_RECEIVED_ACTION");
registerReceiver(iReceiver, iFilter);
}
#Override
protected void onPause(){
unregisterReceiver(iReceiver);
super.onPause();
}
Does anyone know why the broadcast receiver in the main activity doesnt receive the intent? There should be a text displayed in the TextView but it is never shown. thanks for any idea
When receiving the intent via SmsReceiver you can't know if the Activity is up and in what state.
What you should consider is using startActivity(android.content.Intent) from within your SmsReceiver.onReceive(). This way you'll have the same intent object available within Activity.onCreate (just call the getIntent() method)
But if you want to stick to your original design of double broadcasts, then here is your answer.

Background service isn't working properly

I'm trying to implement service in android to make an app locker.
I'm trying to check the which activity is running on the foreground and if it's locked, forwarding it to my Locker activity.
I've added the service in manifest too, but it isn't working at all.
Here's the code `
private static Timer timer = new Timer();
public Boolean userAuth = false;
private Context mContext;
public String pActivity = "";
public IBinder onBind(Intent arg0) {
return null;
}
public void onCreate() {
super.onCreate();
mContext = this;
startService();
}
private void startService() {
timer.scheduleAtFixedRate(new mainTask(), 0, 500);
}
private class mainTask extends TimerTask {
public void run() {
toastHandler.sendEmptyMessage(0);
}
}
public void onDestroy() {
super.onDestroy();
Toast.makeText(this, "Service Stopped ...", Toast.LENGTH_SHORT).show();
}
private final Handler toastHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
String activityOnTop;
ActivityManager manager = (ActivityManager)mContext.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> tasks = manager.getRunningAppProcesses();
//Getting the foreground activity name
activityOnTop=tasks.get(0).processName;
//Checking it against the app I need to lock
if (activityOnTop.equalsIgnoreCase("com.droiddigger.techmanik")) {
Intent lockIntent = new Intent(mContext, Lockscreen.class);
lockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(lockIntent);
} else if(activityOnTop.equalsIgnoreCase("com.droiddigger.applocker")){
}else{
}
}
};
You must start that service. It can be done in an Activity or a BroadcastReceiver.
startService(new Intent(this, UpdaterServiceManager.class));
For example:
public class MyActivity extends Activity {
#Override
public void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
startService(new Intent(this, YourService.class));
finish();
}
}
EDIT:
You are always retrieving the item 0 of the list called tasks. Looking at the SDK documentation, it is said that list order is not especified: https://developer.android.com/reference/android/app/ActivityManager.html#getRunningAppProcesses()
Returns a list of RunningAppProcessInfo records, or null if there are
no running processes (it will not return an empty list). This list
ordering is not specified.
You must get the current visible activity other way. I suggest an AccessibilityService

running non-static method startActivity(Intent) outside of Mainactivity.class

I have a Mainactivity class which has a notificationslistener(seperate class), when a notification appears it calls my gethtml class.They both extend activity but the startactivity in my gethtml class doesnt work... (if i copy and test this code in my MainActivity it works fine).. any ideas why?
This is the main class:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
IntentFilter filter = new IntentFilter();
filter.addAction("com.kpbird.nlsexample.NOTIFICATION_LISTENER_EXAMPLE");
startService(new Intent(MainActivity.this, NLService.class));
Intent intent=new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS");
startActivity(intent);
}
#Override
protected void onDestroy() {
super.onDestroy();
}
}
this is the notification listener
public class NLService extends NotificationListenerService {
#Override
public void onCreate() {
super.onCreate();
IntentFilter filter = new IntentFilter();
filter.addAction("com.kpbird.nlsexample.NOTIFICATION_LISTENER_SERVICE_EXAMPLE");
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
public void onNotificationPosted(StatusBarNotification sbn) {
new Thread(new Runnable() {
public void run(){
Looper.prepare();
int cangethtml = 1;
try{
if(cangethtml==1){
cangethtml = 0; //only runs once
new html();
}
}finally{Looper.loop();}
};
}).start();
}
#Override
public void onNotificationRemoved(StatusBarNotification sbn) {}
}
This is the final class which doesnt open the website through the startactivity.
public class html extends Activity{
public html() {
Intent i2 = new Intent("android.intent.action.MAIN");
i2.setComponent(ComponentName.unflattenFromString("com.android.chrome/com.android.chrome.Main"));
i2.addCategory("android.intent.category.LAUNCHER");
i2.setData(Uri.parse("https://wwww.google.com"));
System.out.println("hello1");
startActivity(i2);
System.out.println("hello2");
}
}
you are trying to start an activity on the constructor of html, thats your problem.
What you can do is to pass the service context to the html class.
Try this:
public html(Context externalContext) {
Intent i2 = new Intent("android.intent.action.MAIN");
i2.setComponent(ComponentName.unflattenFromString("com.android.chrome/com.android.chrome.Main"));
i2.addCategory("android.intent.category.LAUNCHER");
i2.setData(Uri.parse("https://wwww.google.com"));
i2.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
System.out.println("hello1");
externalContext.startActivity(i2); --> START WITH EXTERNAL CONTEXT!!!
System.out.println("hello2");
}
And... injects the notification service context like this:
#Override
public void onNotificationPosted(StatusBarNotification sbn) {
new Thread(new Runnable() {
public void run(){
Looper.prepare();
int cangethtml = 1;
try{
if(cangethtml==1){
cangethtml = 0; //only runs once
new html(NLService.this); --> !!!! inject CONTEXT !!!!
}
}finally{Looper.loop();}
};
}).start();
}
Actually... your html doesn't need to extends Activity at all (actually for me html() should be a method of your notification service not a class).

Categories

Resources