Отключение пользовательского экрана входящего вызова на Android, когда на вызов отвечают или телефон перестает звонить

Я хочу иметь настраиваемый экран входящего вызова, который отображается при входящем вызове и закрывается, если на вызов отвечают или телефон перестает звонить.

Я просмотрел несколько сообщений в Stackoverflow, чтобы показать мне, как я могу это реализовать, и до сих пор я почти достиг цели, и после проверки плюсов и минусов каждого подхода с точки зрения скорости отображения экрана я остановился на WindowManager подход.

Всякий раз, когда я вызываю wm.removeView(ly), я получаю стек ниже

07-08 20:36:41.002  27547-27547/com.testtelephoney.customincomingcall E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.testtelephoney.customincomingcall, PID: 27547
java.lang.IllegalArgumentException: View=android.widget.LinearLayout{7e63aae V.E..... ......I. 0,0-0,0} not attached to window manager
        at android.view.WindowManagerGlobal.findViewLocked(WindowManagerGlobal.java:402)
        at android.view.WindowManagerGlobal.removeView(WindowManagerGlobal.java:328)
        at android.view.WindowManagerImpl.removeViewImmediate(WindowManagerImpl.java:84)
        at com.testtelephoney.customincomingcall.MyPhoneStateListener.onCallStateChanged(MyPhoneStateListener.java:43)
        at android.telephony.PhoneStateListener$2.handleMessage(PhoneStateListener.java:392)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:145)
        at android.app.ActivityThread.main(ActivityThread.java:5832)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399)

Вот мой код:

MyPhoneStateListener.java

import android.content.Context;
import android.graphics.PixelFormat;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;


public class MyPhoneStateListener extends PhoneStateListener{
    Context mContext;
    public MyPhoneStateListener(Context ct) {
        mContext = ct;
    }
    public void onCallStateChanged(int state,String incomingNumber){

        WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
        WindowManager.LayoutParams params = new WindowManager.LayoutParams(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.TYPE_SYSTEM_ALERT|WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL|WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSPARENT);

        params.height= WindowManager.LayoutParams.MATCH_PARENT;
        params.width= WindowManager.LayoutParams.MATCH_PARENT;
        params.format=PixelFormat.TRANSPARENT;
        params.gravity= Gravity.TOP;

        LinearLayout ly;

        final LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        ly=(LinearLayout)inflater.inflate(R.layout.activity_ic,null);


        switch (state){
            case TelephonyManager.CALL_STATE_IDLE:
                Log.d("DEBUG","IDLE");
                if(ly.getVisibility()== View.VISIBLE){
                    wm.removeView(ly);
                }
                break;
            case TelephonyManager.CALL_STATE_OFFHOOK:
                Log.d("DEBUG","OFFHOOK");
                break;
            case TelephonyManager.CALL_STATE_RINGING:
                Log.d("DEBUG","RINGING");
                wm.addView(ly,params);
                break;
        }
    }
}

Сервис-приемник

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;

public class ServiceReceiver extends BroadcastReceiver {
    public ServiceReceiver() {
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        // TODO: This method is called when the BroadcastReceiver is receiving
        // an Intent broadcast.
        MyPhoneStateListener phoneListener = new MyPhoneStateListener(context);
        TelephonyManager telephony = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
        telephony.listen(phoneListener, PhoneStateListener.LISTEN_CALL_STATE);
    }
}

Манифест Android

    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.READ_PROFILE" />
    <uses-permission android:name="android.permission.READ_CONTACTS" />
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
    <receiver android:name=".ServiceReceiver" >
            <intent-filter>
                <action android:name="android.intent.action.PHONE_STATE" />
            </intent-filter>
     </receiver>

person m4r0ck    schedule 08.07.2015    source источник


Ответы (2)


Я добавил флаг, чтобы отметить, что представление было добавлено. Конечно, его нужно улучшать.

 switch (state){
        case TelephonyManager.CALL_STATE_IDLE:
            Log.d("DEBUG","IDLE");
            if (viewCreated) {
                wm.removeView(ly);
                viewCreated = false;
            }
            break;
        case TelephonyManager.CALL_STATE_OFFHOOK:
            Log.d("DEBUG","OFFHOOK");
            break;
        case TelephonyManager.CALL_STATE_RINGING:
            Log.d("DEBUG","RINGING");
            if (!viewCreated){
                WindowManager.LayoutParams params = new WindowManager.LayoutParams(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.TYPE_SYSTEM_ALERT|WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL|WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSPARENT);
                params.height= WindowManager.LayoutParams.MATCH_PARENT;
                params.width= WindowManager.LayoutParams.MATCH_PARENT;
                params.format=PixelFormat.TRANSPARENT;
                params.gravity= Gravity.TOP;

                ly=(LinearLayout)inflater.inflate(R.layout.activity_login,null);
                wm.addView(ly, params);
                viewCreated=true;
            }
            break;
    }
person m4r0ck    schedule 09.07.2015

ly — локальная переменная. Вы создаете новый каждый раз, когда вызывается onCallStateChanged. Вам нужно сохранить макет, который вы добавили в оконный менеджер, в переменной уровня класса, чтобы вы могли удалить экземпляр макета, который вы фактически добавили, а не вновь созданный экземпляр.

person Gabe Sechan    schedule 08.07.2015
comment
Я поместил wm и ly как статические переменные класса и создал экземпляр wm в конструкторе, но та же проблема все еще существует :( - person m4r0ck; 09.07.2015