在Android中叠加窗口服务

时间:2016-05-27 04:12:03

标签: android popup android-service android-broadcastreceiver android-service-binding

我必须实现像True Caller App一样的覆盖窗口。但我得到的问题是,在任何传入或传出呼叫期间,我的服务会自动关闭或销毁。

服务类

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));
    }
}

}

以下是BroadcastReceiver,用于检测Incoming和Outgoing Call,还用于启动和停止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;
        }
    }
}

2 个答案:

答案 0 :(得分:1)

前台服务具有高优先级,因此请尝试将您的服务创建为前台服务并检查其是否有效。要创建前台服务,您需要提供通知,以便用户知道正在进行前台服务。

以下是如何创建foreground service

的方法

但在使服务成为前台之前,请通过查看日志来调试当前服务被杀的原因。

答案 1 :(得分:0)

收到意图后,系统会自动清除BroadcastReceiver的实例。因此,引用的电话服务也将被杀死,使您当前的实现错误反过来在基于您当前实现的某些条件下将调用停止服务并且服务将被销毁。听取呼叫变化,并为每个收到的意图提取信息并传递给服务并在那里处理。