Overlay Window Service In Android
Asked Answered
O

2

11

I have to implement an Overlay Window like True Caller App has.But the problem I am getting is, During any Incoming or Outgoing call my service automatically getting close or destroyed.

Service class

public class OverlayService extends Service implements View.OnClickListener,NotifyHardwareChanges,UpdateSoundDB{

private WindowManager windowManager;
WindowManager.LayoutParams params;
View view;
Button btnEndCall;
public static TextView textView;
public static Context cntxt;

@Nullable
@Override
public IBinder onBind(Intent intent) {
    return null;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    // Let it continue running until it is stopped.
    return START_NOT_STICKY;
}

@Override
public void onCreate() {
    super.onCreate();
    this.cntxt = getApplicationContext();
    windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);

    params= new WindowManager.LayoutParams(
            WindowManager.LayoutParams.MATCH_PARENT,
            WindowManager.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.TYPE_PHONE,
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
            PixelFormat.TRANSLUCENT);

    params.gravity = Gravity.CENTER;
    params.x = 0;
    params.y = 100;

    LayoutInflater inflater = (LayoutInflater)   getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    view = inflater.inflate(R.layout.list_item, null);

    textView = (TextView) view.findViewById(R.id.textView);

    btnEndCall = (Button) view.findViewById(R.id.end_call);
    //btnEndCall.set
    btnEndCall.setOnClickListener(this);


    //this code is for dragging the chat head
    view.setOnTouchListener(new View.OnTouchListener() {
        private int initialX;
        private int initialY;
        private float initialTouchX;
        private float initialTouchY;

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    initialX = params.x;
                    initialY = params.y;
                    initialTouchX = event.getRawX();
                    initialTouchY = event.getRawY();
                    return true;
                case MotionEvent.ACTION_UP:
                    return true;
                case MotionEvent.ACTION_MOVE:
                    params.x = initialX
                            + (int) (event.getRawX() - initialTouchX);
                    params.y = initialY
                            + (int) (event.getRawY() - initialTouchY);
                    windowManager.updateViewLayout(view, params);
                    return true;
            }
            return false;
        }
    });

    windowManager.addView(view, params);
    Utillities.start(OverlayService.this, 1, OverlayService.this);
}

@Override
public void onDestroy() {
    super.onDestroy();
    if (view != null)
        windowManager.removeView(view);

    Utillities.stop(OverlayService.this,1,OverlayService.this);
}

@Override
public void onClick(View v) {
    if(view!=null){
        Utillities.stop(OverlayService.this,1,OverlayService.this);
        windowManager.removeView(view);
        view = null;
    }
}

@Override
public void getNotify(String str) {}

@Override
public void setProcess(double signalEMA) {
    int progress = ((int) signalEMA - Preferences.readInteger(getApplicationContext(), Preferences.CALIBRATION, 0)) ;
    textView.setText("Your Sound Level :" + progress +"db");
    if ((Preferences.readInteger(cntxt, Preferences.SOUND_LEVEL, 0) > 0) && (progress > Preferences.readInteger(cntxt, Preferences.SOUND_LEVEL, 0))) {
        textView.setTextColor(cntxt.getResources().getColor(R.color.red));
    }else{
        textView.setTextColor(cntxt.getResources().getColor(R.color.black));
    }
}

}

And Here following is a BroadcastReceiver to detect the Incoming And Outgoing Call and also being used to Start and Stop Overlayservice.

    public class ServiceReceiver extends BroadcastReceiver{

    TelephonyManager telephonyManager;

    @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2) @Override
    public void onReceive(Context context, Intent intent) {
        // TODO Auto-generated method stub
        if(Preferences.readBoolean(context, Preferences.APP_ON_OFF, false) == true){
            //The other intent tells us the phone state changed.  Here we set a listener to deal with it
            TelephonyManager telephony = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
            telephony.listen(new PhonecallStartEndDetector(context), PhoneStateListener.LISTEN_CALL_STATE);
        }
    }

    public class PhonecallStartEndDetector extends PhoneStateListener {

        int lastState = TelephonyManager.CALL_STATE_IDLE;
        boolean isIncoming;
        Context cntx;

        public PhonecallStartEndDetector(Context context) {
            this.cntx = context;
        }

        //Incoming call-  goes from IDLE to RINGING when it rings, to OFFHOOK when it's answered, to IDLE when its hung up
        //Outgoing call-  goes from IDLE to OFFHOOK when it dials out, to IDLE when hung up
        @Override
        public void onCallStateChanged(int state, String incomingNumber) {
            super.onCallStateChanged(state, incomingNumber);
            if (lastState == state) {
                //No change, debounce extras
                return;
            }
            switch (state) {
                case TelephonyManager.CALL_STATE_RINGING:
                    isIncoming = true;
                    //cntx.startService(new Intent(cntx, OverlayService.class));
                    //Toast.makeText(cntx, "onIncomingCallStarted", Toast.LENGTH_SHORT).show();
                    break;
                case TelephonyManager.CALL_STATE_OFFHOOK:
                    //Transition of ringing->offhook are pickups of incoming calls.  Nothing donw on them
                    if (lastState != TelephonyManager.CALL_STATE_RINGING) {
                        isIncoming = false;
                        cntx.startService(new Intent(cntx, OverlayService.class));
                        //Toast.makeText(cntx, "onOutgoingCallStarted", Toast.LENGTH_SHORT).show();
                    }else{
                        isIncoming = true;
                        cntx.startService(new Intent(cntx, OverlayService.class));
                    }

                    break;
                case TelephonyManager.CALL_STATE_IDLE:
                    //Went to idle-  this is the end of a call.  What type depends on previous state(s)
                    if (lastState == TelephonyManager.CALL_STATE_RINGING) {
                        //Ring but no pickup-  a miss
                        cntx.stopService(new Intent(cntx, OverlayService.class));
                        //Toast.makeText(cntx, "onMissedCall", Toast.LENGTH_SHORT).show();
                    } else if (isIncoming) {
                        cntx.stopService(new Intent(cntx, OverlayService.class));
                        //Toast.makeText(cntx, "onIncomingCallEnded", Toast.LENGTH_SHORT).show();
                    } else {
                        cntx.stopService(new Intent(cntx, OverlayService.class));
                        //Toast.makeText(cntx, "onOutgoingCallEnded", Toast.LENGTH_SHORT).show();
                    }
                    break;
            }
            lastState = state;
        }
    }
}
Orate answered 27/5, 2016 at 4:12 Comment(4)
Could you pls post the stacktrace (using the debugger) on onDetachedFromWindow() method of the view that you add to window manager. Also try change WindowManager.LayoutParams.TYPE_PHONE to TYPE_SYSTEM_ALERT and see if it change anything?Missal
@TinTran, Thanks for your feedback. I need to show an overlay from Service class then I don't know to get stacktrace (using the debugger) on onDetachedFromWindow() method of the view that you add to window manager.Orate
Have you ever write a custom view ? Did you try to change WindowManager.LayoutParams.TYPE_PHONE to TYPE_SYSTEM_ALERTMissal
Yes I have and I changed the WindowManager.LayoutParams.TYPE_PHONE to TYPE_SYSTEM_ALERT.Orate
O
1

Foreground service have high priority , so try creating your service as a foreground service and check if that works. For creating a foreground service you need to provide a notification , so that users are aware that a foreground service is going on.

Here's how you can create a foreground service

But before making your service foreground , debug why your current service is getting killed by checking the logs.

Oma answered 15/6, 2016 at 12:43 Comment(1)
Hi Vins, thanks for your answer. Can you provide me an example. As I am not aware foreground service.Orate
C
0

The instance of the BroadcastReceiver will be cleared automatically by the system after a intent is received. So the referenced telephony service will also be killed, making your current implementation buggy which in turn would under certains conditions based on your current implementation will call stop service and the service would be destroyed. Listen for call changes and for each intent received extract the info and pass to service and handle it there.

Carpetbagger answered 16/6, 2016 at 16:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.