Unable to receive SIP calls when app is killed - android

What should I do to receive SIP calls even when app is in background, exits or restarts?
Currently we're running a foreground service with sticky notification to keep connected with our sip server. This solution isn't completely working
Please help me to achieve this, Thanks in advance!

Firstly, you want a Mainservice that never stops (Even when the device booted, with the help of a bootup receiver).
You have to initialise your sip manager, sip profile and call related codes in the MainService and not in the MainActivity.
Then, You need a BroadCast receiver that receives incoming sip calls. see below example,
public class YourReceiver extends BroadcastReceiver {
SipAudioCall incomingCall = null;
private static YourReceiver instance;
MainService mainService;
public Intent incomingCallIntent;
public static YourReceiver getInstance() {
return instance;
}
/**
* Processes the incoming call, answers it, and hands it over to the
* MainActivity.
* #param context The context under which the receiver is running.
* #param intent The intent being received.
*/
#Override
public void onReceive(final Context context, Intent intent) {
Log.i(TAG, "onReceive: ");
instance = this;
mainService = MainService.getInstance();
try {
SipAudioCall.Listener listener = new SipAudioCall.Listener() {
#Override
public void onRinging(SipAudioCall call, SipProfile caller) {
Log.i(TAG, "onRinging: ");
}
// extra added
#Override
public void onRingingBack(SipAudioCall call) {
Log.i(TAG, "onRingingBack: ");
super.onRingingBack(call);
}
#Override
public void onReadyToCall(SipAudioCall call) {
Log.i(TAG, "onReadyToCall: ");
super.onReadyToCall(call);
}
#Override
public void onError(SipAudioCall call, int errorCode, String errorMessage) {
Log.e(TAG, "onError: errorCode = " + errorCode + ", errorMessage = " + errorMessage);
super.onError(call, errorCode, errorMessage);
}
#Override
public void onChanged(SipAudioCall call) {
Log.i(TAG, "onChanged: ");
super.onChanged(call);
}
#Override
public void onCalling(SipAudioCall call) {
Log.i(TAG, "onCalling: ");
super.onCalling(call);
}
#Override
public void onCallHeld(SipAudioCall call) {
Log.i(TAG, "onCallHeld: ");
super.onCallHeld(call);
}
#Override
public void onCallBusy(SipAudioCall call) {
Log.i(TAG, "onCallBusy: ");
super.onCallBusy(call);
}
#Override
public void onCallEnded(SipAudioCall call) {
Log.i(TAG, "onCallEnded: ");
}
#Override
public void onCallEstablished(SipAudioCall call) {
Log.i(TAG, "onCallEstablished: ");
super.onCallEstablished(call);
}
};
mainService = MainService.getInstance();
incomingCall = mainService.manager.takeAudioCall(intent,listener);
if(mainService.manager.isIncomingCallIntent(intent)){
incomingCallIntent = intent;
}
//starting call screen activity when the receiver receives incoming call
Intent i = new Intent(context, CallActivity.class);
i.putExtra("name", peerName);
i.putExtra("number", peerNumber);
i.putExtra("callType", "Incoming");
context.startActivity(i);
//Sip call received by YourReceiver is assigned to MainService.call so that the MainService can do the further processes.
mainService.call = incomingCall;
} catch (Exception e) {
if (incomingCall != null) {
incomingCall.close();
}
}
}
}

For making a Service run continuously, start a Job scheduler to make this job be a part of android system jobs.
package com.xxx;
import android.app.job.JobParameters;
import android.app.job.JobService;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.util.Log;
import androidx.annotation.RequiresApi;
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class XXJobService extends JobService {
private String TAG = "XXJobService";
private Context context;
public XXJobService() {
}
#Override
public boolean onStartJob(JobParameters params) {
context = this;
try {
if (!MyApp.isServiceRunning(context, MainService.class.getName())) {
Log.i(TAG, "onStartJob : MainService not running so start");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.getApplicationContext()
.startForegroundService(new Intent(context, MainService.class)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));
} else {
context.getApplicationContext()
.startService(new Intent(context, MainService.class)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));
}
}
} catch (Exception e) {
Log.e(TAG, "Exception - MainService not running: " + e.getLocalizedMessage());
}
Log.i(TAG, "onStartJob, returnValue = " + returnValue);
return returnValue;
}
#Override
public boolean onStopJob(JobParameters params) {
boolean returnValue = true;
Log.i(TAG, "onStopJob, returnValue = " + returnValue);
return returnValue;
}
}
Create an Application class in your project that extends Application and define it in your manifest also.
import android.app.ActivityManager;
import android.app.Application;
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.content.ComponentName;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.util.Log;
import java.util.Arrays;
import java.util.List;
public class MyApp extends Application {
Context context;
private static MyApp instance;
static String TAG = "MyApp";
MainService mainService;
JobScheduler jobScheduler;
private static final int JOB_ID = 1;
public static MyApp getInstance() {
return instance;
}
#Override
public void onCreate() {
super.onCreate();
context = this;
instance = this;
Log.i(TAG, "onCreate: ");
// Job scheduler for android version Lolipop(Android 5.0) and above
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
try {
jobScheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);
ComponentName jobService = new ComponentName(getPackageName(), XXJobService.class.getName());
Log.e(TAG, "onCreate: ComponentName : " + jobService );
JobInfo jobInfo = new JobInfo.Builder(JOB_ID, jobService)
.setPersisted(true)
.setPeriodic(5000)
.build();
int jobId = jobScheduler.schedule(jobInfo);
if (jobId == JobScheduler.RESULT_SUCCESS) {
Log.e(TAG, "JobScheduler RESULT_SUCCESS");
// Toast.makeText(context, "Successfully scheduled job : " + jobId, Toast.LENGTH_SHORT).show();
} else {
Log.e(TAG, "JobScheduler RESULT_FAILURE: " + jobId);
// Toast.makeText(context, "RESULT_FAILURE: " + jobId, Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
Log.e(TAG, "JobScheduler Exception : " + e.getLocalizedMessage());
}
}
if (!isServiceRunning(context, MainService.class.getName())) {
try {
Intent intent = new Intent(context, MainService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent);
} else {
startService(intent);
}
} catch (Exception e) {
Log.e(TAG, "Exception startService : " + e.getLocalizedMessage());
}
}
mainService = MainService.getInstance();
Log.e(TAG," MainSerivice : " + mainService);
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread t, Throwable e) {
handleUncaughtException(t, e);
}
});
}
public static boolean isServiceRunning(Context context, String serviceClassName) {
if (context == null || serviceClassName.equalsIgnoreCase("")) {
Log.i(TAG, "isServiceRunning called with context = null or service name blank");
return false;
}
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE);
for (ActivityManager.RunningServiceInfo runningServiceInfo : services) {
if (runningServiceInfo.service.getClassName().equals(serviceClassName))
return true;
}
return false;
}
}
Finally, put a BootUpReceiver to automatically start the notofication and services whenever the phone is restarted. It should have the permission
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<receiver
android:name=".StartupReceiver"
android:enabled="true">
<intent-filter>
<action android:name="com.xx.MainService" />
<action android:name="android.intent.action.ACTION_SHUTDOWN" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<category android:name="android.intent.category.HOME" />
</intent-filter>
</receiver>

Running a service is the right way. You just have to start the activity which will handle your incoming call from the service. The activity can then bind to your service and request all it needs to take over the call. That's actually all you need.

Related

Android: Making Volley HTTP Requests in the background

I am using Volley to make HTTP Calls in my android app. I have a requirement to poll a server every 5 seconds. This should happen even when the app is minimized(or when another app is opened). I am getting timeout errors when the app is minimized and you are on the Home Screen.
here is the code I am using.
AndroidManifest.xml
<application
...
<service android:name=".webviews.services.ScheduledService" android:enabled="true"></service>
</application>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
ScheduledService.java
package com.magic.ultimate_android.webviews.services;
import android.app.Service;
import android.content.Intent;
import android.media.AudioManager;
import android.media.ToneGenerator;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.Volley;
import org.json.JSONObject;
import java.util.Timer;
import java.util.TimerTask;
public class ScheduledService extends Service
{
Timer timer;
private static final String TAG = "ScheduledService";
String valueFromURL = "";
int requestCount = 0;
RequestQueue requestQueue;
#Override
public IBinder onBind(Intent intent)
{
Log.d(TAG, "On Bind called");
return null;
}
#Override
public void onCreate()
{
Log.d(TAG, "On Create called");
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "On Start Command called");
String action = intent.getAction();
if (action.equals("START_TIMER")) {
String urlInput = “https://jsonplaceholder.typicode.com/todos/1”;
String field = “title”;
Log.d(TAG, "Start Timer now******");
startTimer(urlInput, field);
} else if (action.equals("STOP_TIMER")) {
stopTimer();
}
return START_NOT_STICKY;
}
#Override
public void onDestroy()
{
super.onDestroy();
}
private void stopTimer() {
if (timer != null) {
timer.cancel();
}
}
private void startTimer(final String urlInput, final String field) {
timer = new Timer();
requestCount = 0;
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
Log.d(TAG, "URL Input: " + urlInput + ", Field: " + field);
makeServiceCall(urlInput, field);
}
}, 0, 5000);
}
private void makeServiceCall(final String urlInput, final String field) {
Log.d(TAG, "Making Service call...");
RequestQueue requestQueue = getRequestQueue();
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, urlInput, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
Log.d(TAG, "start of response");
if (!response.has(field)) {
return;
}
if ((String) response.get(field).equals(("TARGET_VALUE"))) {
makeServiceCall(urlInput, field);
} else {
if (timer != null) {
timer.cancel();
Log.d(TAG, "Timer is cancelled");
}
// TODO: SEND MESSAGE TO UPDATE THE APP
Intent intent = new Intent(“MESSAGE_TO_MAIN_APP");
// You can also include some extra data.
getApplicationContext().sendBroadcast(intent);
}
} catch (Exception e) {
e.printStackTrace();
Log.e(TAG, e.getMessage());
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
Log.e(TAG, error.toString());
makeServiceCall(urlInput, field);
}
});
jsonObjectRequest.setShouldCache(false);
requestQueue.add(jsonObjectRequest);
}
private RequestQueue getRequestQueue() {
if (requestQueue == null) {
requestQueue = Volley.newRequestQueue(this);
}
return requestQueue;
}
}
MainActivity.java
Intent intent = new Intent(MainActivity.this, ScheduledService.class);
intent.setAction("START_TIMER");
startService(intent);
When the app is open and running, the code works perfectly fine. I see both the logs
Making Service Calls
start of response
But when the app is minimized, I see only the first one. And a volley error
com.android.volley.TimeoutError
Can you please help?

onRecevie method not invoked in BroadcastRecevier

Here,in the OutgoingReceiver its inner onReceive method is not invoking when the class is called.
but when i am calling OutgoingReciver class it is only calling its constructor. not able to call method inside it.
Can connection is established of outgoing call.
How to invoke the class myListener so that it can tell that call is in which state like onCalling, onCallEstablished.
Its manifest file is:
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
<receiver android:name=".OutgoingReceiver">
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
class OutgoingRecevier:-
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.sip.SipAudioCall;
import android.util.Log;
public class OutgoingReceiver extends BroadcastReceiver
{
public OutgoingReceiver()
{
Log.d("outgoing","in outgoing listener");
//this is been called
}
// but not invoking this onRecevie method. Were i am wrong??
#Override
public void onReceive(Context context, Intent intent)
{
Log.d("onRecevice","hi");
String number = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
SipAudioCall.Listener listener = new myListener(context);
}
}
myListener class:-
import android.content.Context;
import android.media.MediaPlayer;
import android.net.sip.SipAudioCall;
import android.net.sip.SipException;
import android.net.sip.SipProfile;
import android.util.Log;
class myListener extends SipAudioCall.Listener {
private Context context;
public myListener(Context context)
{
Log.d("mylistener","i am in");
this.context = context;
}
#Override
public void onRinging(SipAudioCall call, SipProfile caller) {
try {
Log.d("inRinging","in");
call.answerCall(30);
} catch (SipException e) {
e.printStackTrace();
}
}
#Override
public void onReadyToCall(SipAudioCall call) {
Log.d("ReadyCall","IncomingCallReceiver.java onReadyToCall : " + call.toString());
}
#Override
public void onCalling(SipAudioCall call) {
Log.d("Calling","IncomingCallReceiver.java onCalling : " + call.toString());
}
#Override
public void onRingingBack(SipAudioCall call) {
Log.d("RingingBack","IncomingCallReceiver.java onRingingBack : " + call.toString());
}
#Override
public void onCallEstablished(SipAudioCall call) {
Log.d("CallEstablished","IncomingCallReceiver.java onCallEstablished : " + call.toString());
if (call.isInCall()) {
Log.d("CallEstablished","IncomingCallReceiver.java isInCall : " + call.toString());
}
if (call.isOnHold()) {
Log.d("CallEstablished","IncomingCallReceiver.java isOnHold : " + call.toString());
}
if (call.isMuted()) {
Log.d("CallEstablished","IncomingCallReceiver.java isMuted : " + call.toString());
}
call.startAudio();
}
#Override
public void onCallEnded(SipAudioCall call) {
Log.d("CallEnded","IncomingCallReceiver.java onCallEnded : " + call.toString());
}
#Override
public void onCallBusy(SipAudioCall call) {
Log.d("CallBusy","IncomingCallReceiver.java onCallBusy : " + call.toString());
}
#Override
public void onCallHeld(SipAudioCall call) {
Log.d("CallHeld","IncomingCallReceiver.java onCallHeld : " + call.toString());
}
#Override
public void onError(SipAudioCall call, int errorCode, String errorMessage) {
Log.d("CallError","IncomingCallReceiver.java IncomingCallReceiver.java onError : " + call.toString() + "; errorCode: " + errorCode + "; errorMessage: " + errorMessage);
}
#Override
public void onChanged(SipAudioCall call) {
Log.d("CallChanged","IncomingCallReceiver.java onReadyToCall : " + call.toString());
}
}
Mainactivity :-
.
. //code
.
if(TelephonyManager.CALL_STATE_OFFHOOK == state)
{
Log.i("endcallListener hook", "OFFHOOK");
IntentFilter intentFilter = new IntentFilter(Intent.ACTION_NEW_OUTGOING_CALL);
//called here
BroadcastReceiver br = new OutgoingReceiver();
getApplicationContext().registerReceiver(br,intentFilter);
}
.
. //code
.
output:-
I/endcallListener hook: OFFHOOK
D/outgoing: in outgoing listener
//terminated
thanks in advance.
If you want to capture an outgoing call by using TelephonyManager then do this:
TelephonyManager tm = (TelephonyManager)context.getSystemService(Service.TELEPHONY_SERVICE);
tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
PhoneStateListener listener = new PhoneStateListener() {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
// TODO Auto-generated method stub
super.onCallStateChanged(state, incomingNumber);
switch(state) {
case TelephonyManager.CALL_STATE_IDLE:
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
if(incomingNumber==null) {
//outgoing call
} else {
//incoming call
}
break;
case TelephonyManager.CALL_STATE_RINGING:
if(incomingNumber==null) {
//outgoing call
} else {
//incoming call
}
break;
}
}
};

Can someone tell me what is wrong with my android app

I have written an android app which basically allows me to keep track of times and address of GPS coordinates.
I have 3 Lists each corresponding to Lyft, Uber and Other.
But I believe my app starts slowing down my Smart Phone (Samsung Galaxy S7 Edge, with Android O)
can someone look at my code and tell me why is it slowing my smart phone.
My assumption is that, possibly thread synchronization issue.
Attached is my code
1) MainActivity.java
package com.milind.myapp.gpstrackingservice;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Build;
import android.os.PowerManager;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.ActionMode;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity implements AddressListener
{
private static final String TAG = MainActivity.class.getSimpleName();
private PowerManager.WakeLock wakeLock;
private TextView labelAddress;
private TextView multiTextLyft;
private TextView multiTextUber;
private TextView multiTextOther;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
labelAddress = findViewById(R.id.label_address);
multiTextLyft = findViewById(R.id.multi_text_lyft);
multiTextUber = findViewById(R.id.multi_text_uber);
multiTextOther = findViewById(R.id.multi_text_other);
if (MyService.isServiceStarted())
{
MyService.getInstance().load(getSharedPrefs());
refreshAllViews();
}
PowerManager powerManager = (PowerManager) this.getSystemService(Context.POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, "myapp:My Lock");
}
#Override
protected void onStart()
{
super.onStart();
ActivityCompat.requestPermissions(this, new String[]
{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WAKE_LOCK}, 1);
if (!MyService.isServiceStarted())
{
Intent intent = new Intent(this, MyService.class);
intent.setAction(MyService.ACTION_START_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
startForegroundService(intent);
}
else
{
startService(intent);
}
}
}
#Override
public void onWindowFocusChanged(boolean hasFocus)
{
super.onWindowFocusChanged(hasFocus);
if (hasFocus)
{
if (MyService.isServiceStarted())
{
MyService.getInstance().registerAddressListener(this);
}
wakeLock.acquire();
}
else
{
if (MyService.isServiceStarted())
{
MyService.getInstance().unregisterAddressListener(this);
}
wakeLock.release();
}
}
public void onRequestPermissionsResult(int requestCode, String permissions[],
int[] grantResults)
{
switch (requestCode)
{
case 1:
{
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED)
{
}
else
{
// permission denied, boo! Disable the
// functionality that depends on this permission.
}
return;
}
// other 'case' lines to check for other
// permissions this app might request
}
}
#Override
public void onLocationChanged(Location loc)
{
final String address = MyService.getAddress(this, loc);
final CharSequence text = labelAddress.getText();
if (text.toString().equals(address))
{
return;
}
MyService.getInstance().load(getSharedPrefs());
labelAddress.setText(address);
refreshAllViews();
new Tone().play(880);
}
private void refreshAllViews()
{
runOnUiThread(new Runnable()
{
public void run()
{
refereshEditTextLyft();
refereshEditTextUber();
refereshEditTextOther();
}
});
}
private void refereshEditTextLyft()
{
multiTextLyft.setText(MyService.getInstance().getLyftAddresses());
}
private void refereshEditTextUber()
{
multiTextUber.setText(MyService.getInstance().getUberAddresses());
}
private void refereshEditTextOther()
{
multiTextOther.setText(MyService.getInstance().getOtherAddresses());
}
private SharedPreferences getSharedPrefs()
{
return getSharedPreferences("name", MODE_PRIVATE);
}
public void onLyftButtonClicked(View view)
{
MyService.getInstance().addLyftAddress(labelAddress.getText());
new Tone().play(440);
refereshEditTextLyft();
MyService.getInstance().save(getSharedPrefs());
}
public void onUberButtonClicked(View view)
{
MyService.getInstance().addUberAddress(labelAddress.getText());
new Tone().play(440);
refereshEditTextUber();
MyService.getInstance().save(getSharedPrefs());
}
public void onOtherButtonClicked(View view)
{
MyService.getInstance().addOtherAddress(labelAddress.getText());
new Tone().play(440);
refereshEditTextOther();
MyService.getInstance().save(getSharedPrefs());
}
public void onClearButtonClicked(View view)
{
if (MyService.isServiceStarted())
{
SharedPreferences sharedPreferences = getSharedPrefs();
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.clear();
editor.commit();
MyService.getInstance().clear();
refereshEditTextLyft();
refereshEditTextUber();
refereshEditTextOther();
}
}
public void onDelLyftButtonClicked(View view)
{
MyService.getInstance().delLyftEntry();
new Tone().play(440);
refereshEditTextLyft();
MyService.getInstance().save(getSharedPrefs());
}
public void onDelUberButtonClicked(View view)
{
MyService.getInstance().delUberEntry();
new Tone().play(440);
refereshEditTextUber();
MyService.getInstance().save(getSharedPrefs());
}
public void onDelOtherButtonClicked(View view)
{
MyService.getInstance().delOtherEntry();
new Tone().play(440);
refereshEditTextOther();
MyService.getInstance().save(getSharedPrefs());
}
#Override
protected void onRestart()
{
super.onRestart();
}
#Override
public void onActionModeFinished(ActionMode mode)
{
super.onActionModeFinished(mode);
}
#Override
public void onBackPressed()
{
super.onBackPressed();
}
}
2) The MyService.java
package com.milind.myapp.gpstrackingservice;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.provider.Settings;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public class MyService extends Service implements LocationListener
{
private static final String TAG = MyService.class.getSimpleName();
public static final String ACTION_START_SERVICE = "ACTION_START_SERVICE";
public static final String ACTION_STOP_SERVICE = "ACTION_STOP_SERVICE";
public static final String ACTION_UBER = "ACTION_UBER";
public static final String ACTION_LYFT = "ACTION_UBER";
public static final String ACTION_END = "ACTION_END";
public static final String LYFT_PREFIX = "Lyft";
public static final String OTHER_PREFIX = "Other";
public static final String UBER_PREFIX = "Uber";
private static MyService mInstance = null;
private List<AddressListener> listeners = new ArrayList<>();
private List<AddressPoint> lyftAddresses = new ArrayList<>();
private List<AddressPoint> uberAddresses = new ArrayList<>();
private List<AddressPoint> otherAddresses = new ArrayList<>();
private Location mLastLocation;
public MyService()
{
super();
Log.d(TAG, "MyService(): constructor called");
}
public static boolean isServiceStarted()
{
Log.d(TAG, "isServiceStarted()");
return mInstance != null;
}
public static final MyService getInstance()
{
return mInstance;
}
#Override
public IBinder onBind(Intent intent)
{
Log.d(TAG, "onBind(Intent intent)");
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Log.d(TAG, "onStartCommand(Intent, flags, startId) : " + hashCode());
Log.d(TAG, "onStartCommand(...) intent=" + intent + "=" + ", flags=" + flags + ", startId=" + startId);
Log.d(TAG, "onStartCommand(...) isServiceStarted=" + isServiceStarted());
String action = null;
if (intent != null)
{
Log.d(TAG, intent.toString());
action = intent.getAction();
}
else
{
Log.d(TAG, "onStartCommand(...): early return");
return super.onStartCommand(intent, flags, startId);
}
if (isServiceStarted() == false && action == ACTION_START_SERVICE)
{
Log.d(TAG, "onStartCommand(...): Service starting=" + startId);
//startForegroundServivceNotification()
startRunningInForeground();
requestLocationUpdates();
mInstance = this;
Log.d(TAG, "onStartCommand(...): Service started=" + startId);
}
else if (isServiceStarted() == true && action == ACTION_STOP_SERVICE)
{
Log.d(TAG, "onStartCommand(...): Service stopping=" + startId);
stopLocationUpdates();
stopSelf();
Log.d(TAG, "onStartCommand(...): Service stop requested" + startId);
mInstance = null;
}
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy()
{
Log.d(TAG, "onDestroy(): Service destroyed");
super.onDestroy();
mInstance = null;
}
private void stopLocationUpdates()
{
Log.d(TAG, "stopLocationUpdates()");
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationManager.removeUpdates(this);
}
private void requestLocationUpdates()
{
Log.d(TAG, "requestLocationUpdates()");
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
try
{
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 1500, 0, this);
Log.w(TAG, "requestLocationUpdates(): ended gracefully");
}
catch (SecurityException ex)
{
Log.w(TAG, "requestLocationUpdates(): Exception");
ex.printStackTrace();
}
}
#Override
public void onLocationChanged(Location location)
{
Log.v(TAG, "onLocationChanged(Location location): started, location=" + location.toString());
dispatchLocationChange(location);
mLastLocation = location;
Log.v(TAG, "onLocationChanged: completed");
}
private void dispatchLocationChange(Location loc)
{
Log.v(TAG, "dispatchLocationChange(Location)");
for (AddressListener listener : listeners)
{
listener.onLocationChanged(loc);
}
}
public static String getAddress(Context context, Location loc)
{
Log.v(TAG, "getAddress(Location loc) started");
List<Address> addresses;
Geocoder gcd = new Geocoder(context, Locale.getDefault());
try
{
addresses = gcd.getFromLocation(loc.getLatitude(),
loc.getLongitude(), 1);
String strReturnAddress = "";
if (addresses != null && addresses.size() > 0)
{
final Address address = addresses.get(0);
Log.d(TAG, address.toString());
String addressLines = "";
Log.v(TAG, "Locale: " + address.getLocale());
for (int i = 0; i <= address.getMaxAddressLineIndex(); ++i)
{
Log.v(TAG, "AddressLine " + i + ": " + address.getAddressLine(i));
addressLines += address.getAddressLine(i) + ", ";
Log.v(TAG, "addressLines:" + addressLines);
}
String strAddress =
addressLines
;
Log.v(TAG, "strAddress:" + strAddress);
strReturnAddress = strAddress.substring(0, strAddress.length() - 2);
Log.v(TAG, "strReturnAddress:" + strReturnAddress);
}
Log.d(TAG, "getAddress(Location loc) completed with return=" + strReturnAddress);
return strReturnAddress;
}
catch (IOException e)
{
e.printStackTrace();
Log.d(TAG, "Exception", e);
}
Log.d(TAG, "getAddress(Location loc) completed with return=null");
return "";
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras)
{
Log.d(TAG, "onStatusChanged(provider, status, extras): status=" + status + ", extras=" + extras);
}
#Override
public void onProviderEnabled(String provider)
{
Log.d(TAG, "onProviderEnabled(provider) ");
}
#Override
public void onProviderDisabled(String provider)
{
Log.d(TAG, "onProviderDisabled(provider) ");
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
private static void logGetProperties(final String tag, final Object obj)
{
Log.v(tag, "logGetProperties(...)");
Class cls = obj.getClass();
Method[] methods = cls.getMethods();
Log.v(tag, "methods.length = " + methods.length);
for (Method method : methods)
{
String methodName = method.getName();
Log.v(tag, "methodName = " + methodName);
if (methodName.startsWith("get")
&& (method.getParameters() == null || method.getParameters().length == 0)
&& method.getReturnType() != Void.class)
{
try
{
Log.v(tag, methodName + " = " + method.invoke(obj, new Object[0]));
}
catch (Exception ex)
{
Log.e(tag, methodName + " Failed (exception)");
}
}
}
}
public AddressListener registerAddressListener(AddressListener listener)
{
Log.d(TAG, "registerAddressListener(AddressListener)");
if (!listeners.contains(listener))
{
listeners.add(listener);
}
return listener;
}
public AddressListener unregisterAddressListener(AddressListener listener)
{
Log.d(TAG, "unregisterAddressListener(AddressListener)");
if (listeners.contains(listener))
{
listeners.remove(listener);
Log.d(TAG, "unregisterAddressListener(AddressListener): Listener removed");
return listener;
}
Log.d(TAG, "unregisterAddressListener(AddressListener): Listener not found");
return null;
}
public void addLyftAddress(CharSequence text)
{
Log.d(TAG, "addLyftAddress(CharSequence text): text: " + text);
lyftAddresses.add(new AddressPoint(System.currentTimeMillis(), text));
}
public void addUberAddress(CharSequence text)
{
Log.d(TAG, "addUberAddress(CharSequence text): text: " + text);
uberAddresses.add(new AddressPoint(System.currentTimeMillis(), text));
}
public void addOtherAddress(CharSequence text)
{
Log.d(TAG, "addOtherAddress(CharSequence text): text: " + text);
otherAddresses.add(new AddressPoint(System.currentTimeMillis(), text));
}
String getLyftAddresses()
{
return getAddresses(lyftAddresses);
}
String getUberAddresses()
{
return getAddresses(uberAddresses);
}
String getOtherAddresses()
{
return getAddresses(otherAddresses);
}
private String getAddresses(List<AddressPoint> addresses)
{
Log.d(TAG, "getAddresses(List<AddressPoint>)");
String strAddresses = "" + addresses.size() + "\n--------\n";
for (int i = 0; i < addresses.size(); ++i)
{
AddressPoint addresspoint = addresses.get(i);
strAddresses += addresspoint + "\n--------\n";
if ((i % 2) != 0)
{
strAddresses += "\n\n";
}
}
return strAddresses;
}
private void startRunningInForeground()
{
//if more than or equal to 26
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
//if more than 26
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O)
{
String CHANNEL_ONE_ID = "Package.Service";
String CHANNEL_ONE_NAME = "Screen service";
NotificationChannel notificationChannel = null;
notificationChannel = new NotificationChannel(CHANNEL_ONE_ID,
CHANNEL_ONE_NAME, NotificationManager.IMPORTANCE_MIN);
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.RED);
notificationChannel.setShowBadge(true);
notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if (manager != null)
{
manager.createNotificationChannel(notificationChannel);
}
Bitmap icon = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_foreground);
Notification notification = new Notification.Builder(getApplicationContext())
.setChannelId(CHANNEL_ONE_ID)
.setContentTitle("Recording data")
.setContentText("App is running background operations")
.setSmallIcon(R.drawable.ic_launcher_background)
.setLargeIcon(icon)
.build();
Intent notificationIntent = new Intent(getApplicationContext(), MainActivity.class);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
notification.contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent, 0);
startForeground(101, notification);
}
//if version 26
else
{
startForeground(101, updateNotification());
}
}
//if less than version 26
else
{
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle("App")
.setContentText("App is running background operations")
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setOngoing(true).build();
startForeground(101, notification);
}
}
private Notification updateNotification()
{
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
new Intent(this, MainActivity.class), 0);
return new NotificationCompat.Builder(this)
.setContentTitle("Activity log")
.setTicker("Ticker")
.setContentText("app is running background operations")
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentIntent(pendingIntent)
.setOngoing(true).build();
}
public void load(final SharedPreferences lSharedPrefs)
{
Log.w(TAG, "load(SharedPreferences): started");
load(lSharedPrefs, lyftAddresses, LYFT_PREFIX);
load(lSharedPrefs, uberAddresses, UBER_PREFIX);
load(lSharedPrefs, otherAddresses, OTHER_PREFIX);
Log.w(TAG, "load(SharedPreferences): completed");
}
private void load(final SharedPreferences lSharedPrefs, final List<AddressPoint> lAddrPoints, final String lPrefix)
{
Log.w(TAG, "load(SharedPreferences, lAddrPoints, lPrefix)");
lAddrPoints.clear();
final int count = lSharedPrefs.getInt(lPrefix + "Count", lAddrPoints.size());
for (int i = 0; i < count; ++i)
{
String address = lSharedPrefs.getString(lPrefix + "Address" + i, null);
final long time = lSharedPrefs.getLong(lPrefix + "Time" + i, 0);
//if address or time is invalid skip to the next entry
if (address == null || time == 0)
{
continue;
}
final AddressPoint addressPoint = new AddressPoint(time, address);
lAddrPoints.add(addressPoint);
}
}
private void save(final SharedPreferences lSharedPrefs, final List<AddressPoint> lAddrPoints, final String lPrefix)
{
Log.w(TAG, "save(SharedPreferences, lAddrPoints, lPrefix)");
SharedPreferences.Editor editor = lSharedPrefs.edit();
final int count = lAddrPoints.size();
//Save the count
editor.putInt(lPrefix + "Count", count);
for (int i = 0; i < count; ++i)
{
//Save the entry
AddressPoint lAddrPoint = lAddrPoints.get(i);
editor.putLong(lPrefix + "Time" + i, lAddrPoint.getTime());
editor.putString(lPrefix + "Address" + i, (String) lAddrPoint.getAddress());
}
Log.w(TAG, "save(sharedFrefs, List, String): commit");
editor.commit();
}
public void save(final SharedPreferences sharedPreferences)
{
Log.w(TAG, "save(SharedPreferences): started");
Log.w(TAG, "save: lyftAddresses");
save(sharedPreferences, lyftAddresses, LYFT_PREFIX);
Log.w(TAG, "save: uberAddresses");
save(sharedPreferences, uberAddresses, UBER_PREFIX);
Log.w(TAG, "save: otherAddresses");
save(sharedPreferences, otherAddresses, OTHER_PREFIX);
Log.w(TAG, "save(SharedPreferences) completed");
}
public void clear()
{
lyftAddresses.clear();
uberAddresses.clear();
otherAddresses.clear();
}
public void delLyftEntry()
{
if (lyftAddresses.size() > 0)
{
lyftAddresses.remove(lyftAddresses.size() - 1);
}
}
public void delUberEntry()
{
if (uberAddresses.size() > 0)
{
uberAddresses.remove(uberAddresses.size() - 1);
}
}
public void delOtherEntry()
{
if (otherAddresses.size() > 0)
{
otherAddresses.remove(otherAddresses.size() - 1);
}
}
}
3) activity_main.xml
4) AndroidManifest.xml
This (likely) isn't a threading issue, in the normal sense of the word. What's happening is you've got a GeoCoder.getFromLocation() call executing on the main thread. Per the documentation:
The returned values may be obtained by means of a network lookup. ...It may be useful to call this method from a thread separate from your primary UI thread.
That means the method could block for several seconds each time it is called. That's more likely if you're driving through an area of spotty cell coverage. Since the method is called with each location update (roughly every 2 seconds), it's understandable that the UI is hanging.
SUGGESTED FIX
Replace your getAddress() function with an AsyncTask, which moves the getFromLocation() call to a background thread (now your app will truly be multithreaded). Something like this should work:
private class GetFromLocationTask extends AsyncTask<Location, Void, List<Address>> {
protected List<Address> doInBackground(Location... locs) {
return gcd.getFromLocation(locs[ 0 ].getLatitude(), locs[ 0 ].getLongitude(), 1);
}
protected void onProgressUpdate(Void... progress) {}
protected void onPostExecute(List<Address> result) {
//execute the remainder of your getAddress() logic here
}
}
Then, execute it using new GetFromLocationTask().execute(location). Call this instead of getAddress(). You don't need to pass a Context to getAddress(), since Service.this will work just as well (it is a Context).
Bonus hint: Note that onLocationChanged() runs on the UI thread, and so does refreshAllViews(). That means your call to runOnUiThread() is superfluous, and it will just execute the given Runnable synchronously.

NSD Android - Network discovery

Hello I am new to Android Development. I have created an NSD Utility class. Currently its unable to call the method DiscoveryListner. Any help will be great
MainActivity
package com.example.android.implicitintents;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import com.example.android.implicitintents.Utils.NsdUtils;
import java.net.URL;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "NsdChat";
public static String URL_WEB;
NsdUtils mNsdUtils;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
NsdUtils mNsdUtils = new NsdUtils(this);
mNsdUtils.initializeNsd();
}
public void onClickOpenWebpageButton(View view) {
String urlAsString = "http://192.168.10.1";
openWebPage(urlAsString);
}
private void openWebPage(String url) {
Intent intent = new Intent(this, ConfigActivity.class);
intent.putExtra(URL_WEB, url);
Log.d(TAG, "Button Pressed");
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
}
}
NSD Utility Class
package com.example.android.implicitintents.Utils;
import android.content.Context;
import android.net.nsd.NsdServiceInfo;
import android.net.nsd.NsdManager;
import android.util.Log;
public class NsdUtils {
Context mContext;
NsdManager mNsdManager;
NsdManager.ResolveListener mResolveListener;
NsdManager.DiscoveryListener mDiscoveryListener;
public static final String SERVICE_TYPE = "http";
public static final String TAG = "NsdHelper";
public String mServiceName = "Plug_Service";
NsdServiceInfo mService;
public NsdUtils(Context context) {
mContext = context;
mNsdManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);
}
public void initializeNsd() {
initializeResolveListener();
initializeDiscoveryListener();
}
public void initializeDiscoveryListener() {
mDiscoveryListener = new NsdManager.DiscoveryListener() {
#Override
public void onDiscoveryStarted(String regType) {
Log.d(TAG, "Service discovery started");
}
#Override
public void onServiceFound(NsdServiceInfo service) {
Log.d(TAG, "Service discovery success" + service);
if (!service.getServiceType().equals(SERVICE_TYPE)) {
Log.d(TAG, "Unknown Service Type: " + service.getServiceType());
} else if (service.getServiceName().equals(mServiceName)) {
Log.d(TAG, "Same machine: " + mServiceName);
} else if (service.getServiceName().contains(mServiceName)){
mNsdManager.resolveService(service, mResolveListener);
}
}
#Override
public void onServiceLost(NsdServiceInfo service) {
Log.e(TAG, "service lost" + service);
if (mService == service) {
mService = null;
}
}
#Override
public void onDiscoveryStopped(String serviceType) {
Log.i(TAG, "Discovery stopped: " + serviceType);
}
#Override
public void onStartDiscoveryFailed(String serviceType, int errorCode) {
Log.e(TAG, "Discovery failed: Error code:" + errorCode);
mNsdManager.stopServiceDiscovery(this);
}
#Override
public void onStopDiscoveryFailed(String serviceType, int errorCode) {
Log.e(TAG, "Discovery failed: Error code:" + errorCode);
mNsdManager.stopServiceDiscovery(this);
}
};
}
public void initializeResolveListener() {
mResolveListener = new NsdManager.ResolveListener() {
#Override
public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
Log.e(TAG, "Resolve failed" + errorCode);
}
#Override
public void onServiceResolved(NsdServiceInfo serviceInfo) {
Log.e(TAG, "Resolve Succeeded. " + serviceInfo);
if (serviceInfo.getServiceName().equals(mServiceName)) {
Log.d(TAG, "Same IP.");
return;
}
mService = serviceInfo;
}
};
}
public void discoverServices() {
mNsdManager.discoverServices(
SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);
}
}
I tried calling the dicoverService in onclick button event in failed. Do we need to create a Async Task or a new Thread?
first specify the type of TCP network you want to find. Then make the object of the class and call the Intilization and then the discovery function of the NSD.
It should work just fine.
It is not necessary to run this functionality in another thread.
After some investigation current functionality stop crash and start discovery, when change String SERVICE_TYPE = "http"; to public static final String SERVICE_TYPE = "_name._tcp";
You can discover tcp service and then when you will obtain IP just connect to web server via http use those IP adress.

android: The Local Service is running in the UI thread,the same as Activity?

I know the local service runs in the UI thread of the main process, the same as activity.
According to this principle,it shouldn't work immediately when I do something in an activity, if something time-consuming is running in service.
But the example below isn't so.
Who can tell me the truth?
Much appreciate!
package com.example.testservice;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
public class MyService extends Service {
private static final String TAG = "LocalService";
private MyService.LocalBinder binder = new MyService.LocalBinder();
public class LocalBinder extends Binder {
MyService getService() {
return MyService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return binder;
}
#Override
public void onCreate() {
Log.i(TAG, "onCreate");
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "onStartCommand");
//I do something time-consuming in here.
for (int i = 1; i <= 10; i++) {
Log.i(TAG, "Name:" + Thread.currentThread().getName()
+ ".Service i:" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return START_STICKY;
}
#Override
public void onDestroy() {
Log.i(TAG, "onDestroy");
super.onDestroy();
}
#Override
public boolean onUnbind(Intent intent) {
Log.i(TAG, "onUnbind!");
return super.onUnbind(intent);
}
}
Below is the Activity code:
#Override
public void onClick(View v)
{
switch (v.getId())
{
case R.id.btnTimeConsuming:
for(int i = 1;i <= 10; i ++)
{
Log.i(TAG, "Name:" + Thread.currentThread().getName() + ".Activity i:" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
break;
case R.id.btnStartService:
startService(intent);
break;
default:
break;
}
}
When I click the Button "R.id.btnStartService",the I click the Button "R.id.btnTimeConsuming"
It print the below Log.
The task in Service and the task in Service is complicating. Why?

Categories

Resources