SyncAdapter- onPerformSync has no internet access - java

I have a SyncAdapter class that connects to an MQTT broker and publish payload for the server to receive the payload. However, it seems that even though the onPerformSync() method is invoked, the internet access is not there. I thought using SyncAdapter guarantees internet access?
Here is the SyncAdapter Class
public class SyncAdapter extends AbstractThreadedSyncAdapter {
private static final String TAG = SyncAdapter.class.getSimpleName();
private MqttHelper mqttHelper;
public SyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize);
mqttHelper = new MqttHelper(getContext());
}
public SyncAdapter(Context context, boolean autoInitialize, boolean allowParallelSyncs) {
super(context, autoInitialize, allowParallelSyncs);
}
private boolean isNetworkAvailable() {
ConnectivityManager connectivityManager
= (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}
#Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
Log.wtf(TAG, "onPerformSync: ");
Log.wtf(TAG, "SYNC_EXTRAS_MANUAL: " + extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL));
Log.wtf(TAG, "SYNC_EXTRAS_EXPEDITED: " + extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED));
Log.wtf(TAG, "internte: " + isNetworkAvailable());
mqttHelper.connect(new IMqttActionListener() {
#Override
public void onSuccess(IMqttToken asyncActionToken) {
Log.wtf(TAG, "onSuccess: ");
mqttHelper.pub("hello/android", "Finally working via sync adapter praise the lord!!!!");
// TODO: Get Checkpoints from Realm
// TODO: publish at once
// TODO: Disconnect
mqttHelper.disconnect(new IMqttActionListener() {
#Override
public void onSuccess(IMqttToken asyncActionToken) {
Log.wtf(TAG, "onSuccess: disconnect");
}
#Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
Log.wtf(TAG, "onFailure: disocnnect");
}
});
}
#Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
Log.wtf(TAG, "onFailure: ", exception);
}
});
}
#Override
public void onSyncCanceled() {
super.onSyncCanceled();
Log.wtf(TAG, "sync canceled");
}
}
And also a snippet of my Android Manifest pertaining to the MqttService and SyncAdapter:
<application
...
<receiver android:name=".LocationPollingReceiver" />
<service android:name="org.eclipse.paho.android.service.MqttService"
android:process=":sync"/>
<service
android:name=".LocationPollingService"
android:exported="false"/>
<service
android:name=".sync.AuthenticatorService">
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator"/>
</intent-filter>
<meta-data
android:name="android.accounts.AccountAuthenticator"
android:resource="#xml/authenticator" />
</service>
<provider
android:name=".sync.StubProvider"
android:authorities="proj.com.fyp.provider"
android:exported="false"
android:syncable="true"/>
<service
android:name=".sync.SyncService"
android:exported="true"
android:process=":sync">
<intent-filter>
<action android:name="android.content.SyncAdapter"/>
</intent-filter>
<meta-data android:name="android.content.SyncAdapter"
android:resource="#xml/syncadapter" />
</service>
</application>
Does this have anything to do with invoking the sync manually? like what I did below?
Account mAccount = MainActivity.CreateSyncAccount(context);
Bundle settingsBundle = new Bundle();
settingsBundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
settingsBundle.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
//settingsBundle.putBoolean(ContentResolver.SYNC_EXTRAS_FORCE, true);
ContentResolver.requestSync(mAccount, AUTHORITY, settingsBundle);
Even syncing via the Settings->Account->Sync now produced the same result.

Let me explain something.
onPerformSync() is a callback, which is not up to your control on how/when it gets called? These types of callbacks are generally Async Tasks, which can be triggered from external (can be remote) objects anytime. That's why we generally put these types of callbacks in our MainThread (UI thread) because, MainThread can't be killed throughout the app. [Note: If you have executed a service in the different process then you can run onPerformSync() from that Service as well]. My intention of saying this is to make sure that throughout the app keeps running, there is a change of these callbacks can be executed anytime.
I really don't see any use of onNetworkAvailable() method here. You use this onNetworkAvailable() if you want to do some network operations from your side.

Related

Firebase massaging

I am trying to handle the messaged from FCM(Firebase Cloud Messaging) in andorid;
This is my code
FirebaseMessaging.getInstance().getToken()
.addOnCompleteListener(new OnCompleteListener<String>() {
#Override
public void onComplete(#NonNull Task<String> task) {
if (!task.isSuccessful()) {
Log.w("TAG", "Fetching FCM registration token failed", task.getException());
return;
}
// Get new FCM registration token
String token = task.getResult();
// Log and toast
Log.d("TAG", token);
Toast.makeText(StartActivity.this, token, Toast.LENGTH_SHORT).show();
}
});
FirebaseMessaging.getInstance().setAutoInitEnabled(true);
And i have send messaged from firebase console.
But i want to handle the messages.
So i'have did this doc says https://firebase.google.com/docs/cloud-messaging/android/receive
This is manifest.xml
<service
android:name="com.google.firebase.messaging.FirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="#android:drawable/ic_notification_overlay" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="#color/white" />
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
This is my FirebaseMessagingService extended class
public class MessageService extends FirebaseMessagingService {
private static final String TAG = "MessageService";
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Toast.makeText(this, "Got it", Toast.LENGTH_SHORT).show();
}
}
But I don't know how to resgister this FirebaseMessagingService class to Firebase messaging
You don't need to register the class of your messaging service, you need to register the application itself. It should be google-services.json configuration file in your project with all necessary info about the project in firebase console. It will make kind of connection between your app and project created in Firebase console.
There are several ways to get this configuration file:
Generate google-services.json via Firebase console https://firebase.google.com/docs/cloud-messaging/android/client#register_your_app_with_firebase
Generate it via Android studio. Tools -> Firebase -> Cloud messaging -> complete wizard "Setup Firebase cloud messaging"
You have done a mistake in manifest.xml file.
You had to replace this
<service
android:name="com.google.firebase.messaging.FirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="#android:drawable/ic_notification_overlay" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="#color/white" />
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
with this
<service android:name=".helpers.MyFirebaseInstanceIDService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
<service android:name=".helpers.MyFirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
and create these classes
MyFirebaseInstanceIDService
public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {
public void onTokenRefresh() {
// Get updated InstanceID token.
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
Log.d("TAG", "Refreshed token: " + refreshedToken);
// If you want to send messages to this application instance or
// manage this apps subscriptions on the server side, send the
// Instance ID token to your app server.
}
}
and MyFirebaseMessagingService
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "DEEDDEED";
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
public void run() {
Toast.makeText(MyFirebaseMessagingService.this,"Hello",Toast.LENGTH_SHORT).show();
}
});
// ...
// TODO(developer): Handle FCM messages here.
Log.d(TAG, "From: " + remoteMessage.getFrom());
// Check if message contains a data payload.
if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "Message data payload: " + remoteMessage.getData());
if (/* Check if data needs to be processed by long running job */ true) {
// For long-running tasks (10 seconds or more) use Firebase Job Dispatcher.
// scheduleJob();
} else {
// Handle message within 10 seconds
// handleNow();
}
}
// Check if message contains a notification payload.
if (remoteMessage.getNotification() != null) {
Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
}
// Also if you intend on generating your own notifications as a result of a received FCM
// message, here is where that should be initiated. See sendNotification method below.
}
#Override
public void onNewToken(#NonNull String s) {
super.onNewToken(s);
HashMap<String,String> map = new HashMap<>();
Database database = new Database(getApplicationContext());
map.put("user",database.getPhone());
map.put("token",s);
Call<Void> call = new Server().getRetrofitInterface().executeUpdatePTK(map);
call.enqueue(new Callback<Void>() {
#Override
public void onResponse(Call<Void> call, Response<Void> response) {
}
#Override
public void onFailure(Call<Void> call, Throwable t) {
}
});
}
}

Unable to add window in BroadcastReceiver

I am trying to send e-mai in background. I am using this library:library to achieve this, so i've created BroadcastReceiver with library code. But unfortunately i've got errror when i try to send e-mail:Unable to add window -- token null is not valid; is your activity running? I am trying to pass context from Activity, to BroadcastReceiver, but i think that context in Receiver is some kind of seperate only for this statement. Any advice to avoid this error?
Manifest
<receiver
android:name=".service.EmailReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="BackgroundProcessEmail" />
</intent-filter>
</receiver>
BroadcastReceiver
#Override
public void onReceive(final Context context, Intent intent) {
String email=intent.getStringExtra("email");
String password=intent.getStringExtra("password");
String deviceModel = Build.MANUFACTURER
+ " " + Build.MODEL;
assert email != null;
assert password != null;
BackgroundMail.newBuilder(context)
.withUsername(email)
.withPassword(password)
.withSenderName("Full")
.withMailTo("email")
.withType(BackgroundMail.TYPE_PLAIN)
.withSubject("Your device " + deviceModel +" achieved")
.withBody("")
.withSendingMessage("Sending email")
.withOnSuccessCallback(new BackgroundMail.OnSendingCallback() {
#Override
public void onSuccess() {
}
#Override
public void onFail(Exception e) {
Toasty.error(context, "E-mail sent error" + e.getMessage(), Toasty.LENGTH_LONG).show();
}
})
.send();
}

Not able to connect with a Service

I'm trying to create a service that handles networking in my app. I followed all the steps in https://developer.android.com/reference/android/app/Service and https://developer.android.com/guide/components/bound-services#Binding, but the activity doesn't seem to connect with the service.
Here is the SocketService, which has the TcpClient object that connects to my server using sockets:
public class SocketService extends Service{
TcpClient tcpClient = new TcpClient();
private final IBinder mBinder = new LocalBinder();
/**
* Class used for the client Binder. Because we know this service always
* runs in the same process as its clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder {
SocketService getService() {
// Return this instance of LocalService so clients can call public methods
return SocketService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/*
* Client methods
*/
public void connect(MyCallback callback, String ip, int port){
tcpClient.connect(callback, ip, port);
}
public String disconnect(){
return tcpClient.disconnect();
}
public String send(String data){
return tcpClient.send(data);
}
public String recv(){
return tcpClient.recv();
}
}
Here is my main activity:
public class MainActivity extends AppCompatActivity {
SocketService socketService;
boolean bound = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onStart(){
super.onStart();
Intent serviceIntent = new Intent(MainActivity.this, SocketService.class);
if(bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE)){
Toast.makeText(getApplicationContext(), "bound", Toast.LENGTH_LONG);
}
if(bound) {
socketService.connect(this, ip, port);
} else {
Toast.makeText(getApplicationContext(), "not bond", Toast.LENGTH_LONG).show();
}
}
/*
* Service callback
*/
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
Toast.makeText(getApplicationContext(), "ServiceConnection", Toast.LENGTH_LONG);
socketService = ((SocketService.LocalBinder) service).getService();
bound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
socketService = null;
bound = false;
}
};
}
And the AndroidManifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.drrbarrera.home">
<uses-permission android:name="android.permission.INTERNET" />
<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>
<service
android:name=".SocketService"
android:enabled="true"
android:exported="true">
</service>
</application>
</manifest>
As I said before, the MainActivity doesn't seem to connect. "socketService" (in the MainActivity) stays null and "bound" stays false, like if "mConnection" wasn't being executed. Any idea of what might be wrong?
Any help is appreciated.
Thanks in advance!
The call to bindService() returns a boolean result telling you whether the bind is successful (really, it means in progress). The operation is asynchronous, even within the same process (which is what your LocalBinder is.)
In other words, the binding is not complete until your ServiceConnection.onServiceConnected() is called back. Once that callback is hit and you get the service binder, then you can call through to the backing service.
A few other notes to help you out:
Since your Service is running in the same process as your Activity, the calls are direct and not using binder threads. This will have an effect on your Activity code.
Blocking calls should not be main on your main (UI) thread. This means if your Activity code is going to call socketService.connect(), it will need to do it from a background thread. Otherwise, you will get an exception as Android now prevents network I/O on the main thread. Other types of blocking operations can result in an ANR, which will result in your app crashing.
If your network I/O is for REST or other HTTP related traffic, look at using Retrofit or Volley as they are highly performant, extensible and deal with network and HTTP related heavy lifting for you.

Android Redmi 6A issues - Failed to connect to the server trigger by Event BOOT_COMPLETED

I have problem with specific device REDMI 6A (with OS MIUI Android Oreo 8.1), according to my project. it's simple application, only connect to the server trigger by BOOT_COMPLETED event. i try to check the internet connection is connected or not. it is really weird the Redmi 6A can't connect,but when i test with MI A1 (OS Android Oreo 8.1 - Android One) the device can connect as well. I really don't understand why this can be happen. I really appreciate if some one can advice me.
This Below the code.
AndroidManifest.xml
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.NETWORK" />
....................
<service
android:name=".services.SocketJobIntentService"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE" android:label="#string/socket_job" />
<receiver
android:name=".broadcast.MainBroadCastReceiver"
android:enabled="true"
android:label="#string/receiver_name">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<service
android:name=".services.SocketSvc"></service>
SocketJobIntentService.java
public class SocketJobIntentService extends JobIntentService {
static Context context;
static final int JOB_ID = 1000;
public static void enqueueWork(Context _context, Intent work) {
context = _context;
enqueueWork(_context, SocketJobIntentService.class, JOB_ID, work);
}
public boolean isOnline(Context context) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
//should check null because in airplane mode it will be null
return (netInfo != null && netInfo.isConnected());
}
#Override
protected void onHandleWork(#NonNull Intent intent) {
if(context==null){context = this;}
boolean isInternetConnected = isOnline(context);
if(isInternetConnected) {
Log.d("DT_JobIntentService","Executed!! and try to Calling Another Service 'SocketSvc' !!!");
Intent service = new Intent(this,SocketSvc.class);
startService(service);
}else{
Log.e("DT_WeGetEcon","isInternetConnected=false !!!!!! LOL!");
}
}}
MainBroadCastReceiver.java
public class MainBroadCastReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, Intent intent) {
try {
String action = intent.getAction();
if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
Log.d("DT_MainBroadCastRceiver", action+" Called !!!");
SocketJobIntentService.enqueueWork(context, new Intent());
Log.d("DT_JobIntent","Try to call JobIntent");
}
}
catch (Exception exc){
Log.e("DT_ERR_ACTBOOT_COMPLTED",exc.getMessage());
}
}}
LogCat
LogCat MI A1
LogCat RedMI 6A
I really appreciate if anyone can advice me.
Thanks
Finally, I found my own solution.
Just put two line code inside onReceive MainBroadCastReceiver.java
public void onReceive(final Context context, Intent intent) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
ref to : Error StrictMode$AndroidBlockGuardPolicy.onNetwork

Obtaining list of connected bluetooth low energy devices in android 3.1 and later

I'm working on application which shows list of certain connected bluetooth low energy devices, so user can choose which one of them he wants to configure.
The problem is that you can't just list all connected devices. As far as I know there are three possible ways:
Use BluetoothProfiles
bluetoothManager.getConnectedDevices(BluetoothProfile.GATT_SERVER);
This fails because android won't connect to GATT server, when device connects, so device is neither under GATT_SERVER nor GATT profile. However once I call connectGatt method,
bluetoothDevice.connectGatt(getApplicationContext(), false, gattCallback);
device can be found under both GATT_SERVER and GATT profile. Other profiles are not supported by low energy devices.
List paired devices and try connectGatt on each of them
List<BluetoothDevice> connectedDevices = new ArrayList<BluetoothDevice>();
for(BluetoothDevice device : bluetoothAdapter.getBondedDevices()) {
BluetoothGatt gatt = device.connectGatt(getApplicationContext(), false, gattCallback);
if(gatt != null) {
connectedDevices.add(device);
}
gatt.disconnect();
}
This method cannot be used as it cannot determine if device is already connected or only in range but not connected
On system boot start service listening to ACL_CONNECTED and ACL_DISCONNECTED intents and maintaining list of connected devices
Manifest
<service android:name=".ManagerService" android:enabled="true" />
<receiver
android:name=".BootFinishedReceiver"
android:directBootAware="true"
android:enabled="true"
android:exported="false"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
Receiver
public class BootFinishedReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent serviceIntent = new Intent(context, ManagerService.class);
context.startService(serviceIntent);
}
}
Service
public class ManagerService extends Service {
private static List<BluetoothDevice> connectedDevices;
#Override
public void onCreate() {
connectedDevices = new ArrayList<BluetoothDevice>();
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
registerReceiver(connectionReceiver, filter);
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy() {
unregisterReceiver(connectionReceiver);
super.onDestroy();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
private final BroadcastReceiver connectionReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if(BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) {
connectedDevices.add(device);
}else{
connectedDevices.remove(device);
}
}
};
public static List<BluetoothDevice> getConnectedDevices() {
return connectedDevices;
}
}
Since 3.1 apps can no longer receive system intents before activity is started, so this cannot be used either.
Is there any other way or how can I achieve it now in later android versions?
Thanks for any suggestions
Well, I found out that you can still use ON_BOOT_COMPLETED, but you have to allow it in setting on your device. So my problem is solved

Categories