I have a skeleton class of JobIntentService
public class BackgroundRequestService extends JobIntentService {
/**
* Unique job ID for this service.
*/
static final int JOB_ID = 1234;
public static void enqueueWork(Context context, Intent work) {
BackgroundRequestService.enqueueWork(context, BackgroundRequestService.class, JOB_ID, work);
}
#Override
protected void onHandleWork(#NonNull Intent intent) {
if (intent.getExtras() != null){
String x = ";";
}
}
}
I have included the Service in the manifest
<service android:name=".BackgroundRequestService"
android:enabled="true"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="false" />
And calling the proper enqueue method
Intent intent = new Intent();
intent.putExtra("hardware", hardware);
BackgroundRequestService.enqueueWork(context, intent);
But the onHandleWork is never getting called. i have looked at all the pages about setting the services correctly and making sure onBind isn't overridden, but this still isn't working, wondering if another set of eyes would spot something ive missed. Thank you
Try to start service this way:
ComponentName comp = new ComponentName(context.getPackageName(), BackgroundRequestService.class.getName());
BackgroundRequestService.enqueueWork(context, (getIntent().setComponent(comp)));
Found the issue through some proper looking into the Logcat
Turns out the "hardware" that i was putting into my Intent was missing a field to be Serialized.
This caused this message to appear in the Logcat
I/UDP: no longer listening for UDP broadcasts cause of error Parcelable encountered IOException writing serializable object (name = Project.Hardware)
After fixing this Serialization issue i was able to call the onHandleWork() method.
Related
In my Android application, I am using One Signal push notification service to send push notifications. I have done all the settings according to document as mentioned.
After setting up all these things, I have created one service class of one signal like below-
NotificationExtenderBareBonesExample.java
public class NotificationExtenderBareBonesExample extends NotificationExtenderService {
public static String first_screen;
#Override
protected boolean onNotificationProcessing(OSNotificationReceivedResult receivedResult) {
SharedPreferences.Editor editor = getApplicationContext().getSharedPreferences("NOTIFY_PREF", MODE_PRIVATE).edit();
editor.putString("notify_msg", receivedResult.payload.groupMessage);
editor.putString("notify_key", receivedResult.payload.groupKey);
editor.apply();
first_screen = receivedResult.payload.groupMessage;
return false;
}
}
I have also created another class to handle the received push notification like below-
ExampleNotificationReceivedHandler.java
public class ExampleNotificationReceivedHandler implements OneSignal.NotificationReceivedHandler {
#Override
public void notificationReceived(OSNotification notification) {
JSONObject data = notification.payload.additionalData;
String customKey;
if (data != null) {
customKey = data.optString("customkey", null);
if (customKey != null)
Log.i("OneSignalExample", "customkey set with value: " + customKey);
}
}
}
Then, in my Activity class, I have initialized One Signal like below-
OneSignal.startInit(this)
.inFocusDisplaying(OneSignal.OSInFocusDisplayOption.Notification)
.unsubscribeWhenNotificationsAreDisabled(true)
.setNotificationReceivedHandler(new ExampleNotificationReceivedHandler())
.setNotificationOpenedHandler(new MyNotificationOpenedHandler(this))
.init();
At last in my AndroidManifest file, I have declared the service like below-
<service
android:name="com.rokomari.new_package.notification_check.NotificationExtenderBareBonesExample"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE">
<intent-filter>
<action android:name="com.onesignal.NotificationExtender" />
</intent-filter>
</service>
The push notification was coming, if the app is being used recently, but the problem was still there as it is mentioned in my question. So, I have checked few more solutions and applied in my project like below-
I made my application a system app and added one authentication service with that.
I also added one Broadcast-Receiver class like below-
BootReceiver.java
public class BootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
Intent startServiceIntent = new Intent(context, NotificationExtenderBareBonesExample.class);
context.startService(startServiceIntent);
Intent notificationServiceIntent = new Intent(context, NotificationExtenderBareBonesExample.class);
context.startService(notificationServiceIntent);
}
}
}
And declared this in my AndroidManifest file-
<receiver
android:name="com.rokomari.new_package.notification_check.BootReceiver"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
After doing all these I am still having the same problem.
---- The Problem is -----
When I am using app(opening the app) regaularly the push notification from one signal is coming whether the app is in background or not. But when I am not using the app for a while it's not coming. In addition, for some devices mainly Xiomi the push notification is not coming at all.
After making some changes in Xiomi device like below-
*** Xiaomi - Make sure "Auto-start" property enabled for your app in the settings.**
After changing settings, the push notification came once. But I need a solution programmatically to send push notification to cover all the devices. If it is not possible yet with One Signal, then I like to know how apps like facebook, whatsapp send push notification?
I am trying to send primitive data from a class extending IntentService to a class extending a BroadcastReceiver, however, data received in the BroadcastReceiver is null.
In my IntentService class, I have the following code
Intent smsListener = new Intent(ScheduledRepliesService.this, SmsListener.class);
smsListener.putExtra("reply", reply);
smsListener.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startService(smsListener);
I can guarantee that reply is not null in IntentService class.
I retrieve it in onReceive method in BroadcastReceiver class with
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Telephony.Sms.Intents.SMS_RECEIVED_ACTION)) {
String replyMessage = intent.getStringExtra("reply");
...
}
...
}
I have declared the receiver in Manifest.xml file
<receiver android:name=".utilities.sms.SmsListener">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
and can confirm that if replyMessage string is not null, code produces no errors.
I would appreciate your help, thank you.
Although I was not able to find an answer to my problem, I did a bit of a workaround, and it does solve my problem. I hope this answer will be useful for somebody else as well.
I have a foreground service responsible for creating notifications when SMS message is received and a broadcast receiver whose task is to return said message body and sender number.
I was thinking in the wrong direction, sending data from service to receiver, but it should be the other way around.
Create an interface
public interface SmsListener {
public void messageReceived(String messageSender, String messageText);
}
and use this code in broadcast receiver
public class SmsBroadcastReceiver extends BroadcastReceiver {
//Interface
private static SmsListener smsListener;
#Override
public void onReceive(Context context, Intent intent) {
//Get data to a Bundle
Bundle data = intent.getExtras();
//PDUs represent received SMS message(s)
assert data != null;
Object[] pdus = (Object[]) data.get("pdus");
for (int i = 0; i < pdus.length; i++) {
//Reconstruct SMS message from pdus object
SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) pdus[i]);
String sender = smsMessage.getDisplayOriginatingAddress();
String messageBody = smsMessage.getDisplayMessageBody();
//SmsListener's callback method
smsListener.messageReceived(sender, messageBody);
}
}
//Bind listener for the use in ScheduledRepliesService
public static void bindListener(SmsListener listener) { smsListener = listener; }
}
and lastly, retrieve the SMS message contents and sender number (as string) in service
//Get SMS message data from SmsBroadcastReceiver
SmsBroadcastReceiver.bindListener(new SmsListener() {
#Override
public void messageReceived(String messageSender, String messageText) {
//TODO: do something in here
....
});
I am trying to write an app that checks in with a server every X seconds.
I was able to make it work, but only when the application is running and active (not sure if it can be minimized, was not able to test it clearly) and the device is not locked. I would like for the checking to continue even if I lock the device or do other things on it.
From my searches, it seems like I should use service, but I was not able to figure out how to implement it with what I am trying to do. Or is there something else that could do this?
What I need to and failed to do is this:
User checks a CheckBox - start the service
Create the service and pass some information to it
Create an instance of my class in the service using the passed information
Call this instance's method every X seconds in a new thread (the method returns true/false)
Listen to ?something and if the method returns true then stop the service and notify user
If the user unchecks the CheckBox, stop the service.
I tried doing this, but I was unable to get any information out of the thread and out of the service. Is there a way to do so?
Starting the service from activity for example and binding it with your app
//make these 2 variables as fields in Activity for example
YourService yourService = null;
//this variable can be used for checking if your activity are binded already or not
boolean mBounded = false;
Intent mIntent = new Intent(this, YourService.class);
startService(mIntent);
bindService(mIntent, mConnection, BIND_AUTO_CREATE);
ServiceConnection mConnection = new ServiceConnection() {
public void onServiceDisconnected(ComponentName name) {
mBounded = false;
yourService = null;
}
public void onServiceConnected(ComponentName name, IBinder service) {
mBounded = true;
YourService.LocalBinder mLocalBinder = (YourService.LocalBinder) service;
yourService= mLocalBinder.getServerInstance();
}
};
Do not forget that you can use methods from Service in Activity only after it is bound to your Activity. In other words it is available only after onServiceConnected is executed.
So you have now service and activity who can communicate with each other.
For example you can call in Activity some public method of your Service, like
if (yourService != null)
yourService.test();
If you want to call your Activity methods in Service you should pass it to Service with simple setter.
If you want to stop Service its kinda easy too:
Intent mIntent = new Intent(this, YourService.class);
stopService(mIntent);
For doing request every X service:
1) You can do infinity separate thread inside Service and do request after delay for X seconds.
2) For checking every X seconds you can use something like AlarmManager.
3) Also its possible to use CountDownTimer inside your Service to do some requests to server.
If you want to create your Service after reboot if CheckBox was set, its easy too. So you should use simple BroadcastReceiver.
First of all you should save your CheckBox setting in SharedPreferences, then run your Service if you need.
public class SimpleReceiver extends WakefulBroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
//run below code if you need, depends on your saved value of Checkbox in SharedPreferences
Intent serviceIntent = new Intent(context, YourService.class);
context.startService(serviceIntent);
}
}
And for sure dont forget to add in AndroidManifest information about your Service and Receiver to be sure it will run automatically after reboot.
<service
android:name=".package.YourService"
android:enabled="true"
android:exported="false"> </service>
<receiver
android:name=".package.SimpleReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action adroid:name="android.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>
I've been struggling with this problem for days now. I know there are a lot of questions with the same problem on SO but i couldn't get it to work.
What I have done
Uploaded APK in beta phase
Created Merchant account
Added test user
Code
AndroidManifest.xml
<uses-permission android:name="com.android.vending.BILLING" />
MainActivity.java
public class MainActivity extends AppCompatActivity {
private IabHelper mHelper;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// ...
setupInAppBillings();
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
super.onActivityResult(requestCode, resultCode, data);
}
}
// [....]
private void setupInAppBillings() {
String base64EncodedPublicKey = "MY PUBLIC KEY";
mHelper = new IabHelper(this, base64EncodedPublicKey);
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
if (!result.isSuccess()) {
Toast.makeText(getContext(), "In-app Billing setup failed: " + result, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getContext(), "In-app Billing is set up OK", Toast.LENGTH_SHORT).show();
}
}
});
}
}
Tested on
Huawei P8 (Google Play Version 6.2.14)
In Switzerland, so a supported country for In-App Billing
What I've tried
Deleted cache and data from Google Play
Tutorial from Google Developer site
Went trough the checklist from user sokie: answer of sokie
The only thing I haven't done from this list is the setup of the License Verification Library (LVL). But I couldn't find any information that this step is required for an In-App Purchase. If not needed I want to do it without this library because I don't really need it as stated on the Google Site.
The Google Play Licensing service is primarily intended for paid applications that wish to verify that the current user did in fact pay for the application on Google Play.
Is there something I miss?
if you target android 31 you should add this to your manifest :
<queries>
<intent>
<action android:name="android.intent.action.MAIN" />
</intent>
</queries>
Finally I got it to work! The problem was the following: Even though I put the IInAppBillingService.aidl in the com.android.vending.billing package, the generated class was in the wrong package as you can see in the code below.
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: C:\\path\\src\\main\\aidl\\com\\android\\vending\\billing\\IInAppBillingService.aidl
*/
package billing;
public interface IInAppBillingService extends android.os.IInterface { //... }
To solve this, I deleted and recreated the com.android.vending.billing package with the IInAppBillingService.aidl. So if you have the same problem, check twice where the IInAppBillingService.java was generated.
I recently faced this problem. As Bona Fide wrote, the package declaration in IInAppBillingService.aidl must be set to "com.android.vending.billing" and the aidl file should be found inside the corresponding directory using the explorer. Furthermore (and that was the problem in my case), in the IabHelper.java, the string parameter to serviceIntent must be the same as the package name that contains the IInAppBillingService.aidl file.
Intent serviceIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND");// correct package name: com.android.vending.billing
serviceIntent.setPackage("com.android.vending");
List<ResolveInfo> intentServices = mContext.getPackageManager().queryIntentServices(serviceIntent, 0);
if (intentServices != null && !intentServices.isEmpty()) {
// service available to handle that Intent
mContext.bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE);
}
else {
// no service available to handle that Intent
if (listener != null) {
listener.onIabSetupFinished(
new IabResult(BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE,
"Billing service unavailable on device."));
}
}
}
I am trying to develop an app where it will turn on your ringer if someone calls you a certain amount of times in a row in a certain period of time. This is my first real app, so I'm a little stuck.
How would I record whenever a call is received in an internal list? Would this need to be a service to always be running, or could this work in a normal app by just receiving the intent of the dialer app?
I apologize if this question is a little vague.
The best way to do it is, by declaring your broadcast receiver in the manifest, this will cause that the code on your BroadcastReceiver class to get executed everytime the event is fired, without the need of a service running in the background all the time, let the OS handle the observing part for you...
<receiver android:name=".ReceiverExample">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
Now, in your broadcastreceiver class "ReceiverExample", create a SharedPreference to store the number of incomming calls, and based on that, you can validate if is time to do something else or not...
public class ReceiverExample extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//Logic to listen incoming calls, and keep track of them using Shared Preferences..
}
}
Services are good for long tasks but the OS it self is well suited to Monitor/Observe events (like Telephony events e.g. Incomming calls...), try not to re-do the OS work by creating Services just to monitor already known events...
Regards
use single Tone Class for recording
public class Recording {
private static MediaRecorder recorder;
private File audiofile;
private static Recording mInstance;
public MediaRecorder getRecorder() {
System.out.println("From singleton..!!!");
return recorder;
}
public static Recording getInstance(Context context) {
return mInstance == null ? (mInstance = new Recording(context))
: mInstance;
}
private Recording(Context context) {
System.out.println("Again initiated object");
File sampleDir = Environment.getExternalStorageDirectory();
try {
audiofile = File.createTempFile("" + new Date().getTime(), ".amr",
sampleDir);
} catch (IOException e) {
e.printStackTrace();
return;
}
recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
recorder.setOutputFile(audiofile.getAbsolutePath());
}
}