it-swarm.com.ru

Всплывающее окно над родным экраном входящих вызовов Android, как в Android-приложении

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

Я закончил этот код. Но теперь проблема в том, что на Android 4.1 (Jelly bean) API-уровне 17 когда телефон звонит, PHONE_STATE приходит как OFF HOOK, и если я вызываю активность, она вызывается, но код под ней не выполняется Я перечисляю код:

Мой приемник вещания

package com.example.popwindowonincomingcallscreen;

import Java.util.concurrent.Executors;
import Java.util.concurrent.ScheduledExecutorService;

import Android.content.BroadcastReceiver;
import Android.content.Context;
import Android.content.Intent;
import Android.telephony.TelephonyManager;
import Android.util.Log;

public class IncomingBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        Log.d("IncomingBroadcastReceiver: onReceive: ", "flag1");

        String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
        Log.d("IncomingBroadcastReceiver: onReceive: ", state);
        if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)
                || state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) {

            Log.d("Ringing", "Phone is ringing");

            Intent i = new Intent(context, IncomingCallActivity.class);
            i.putExtras(intent);
            i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
            Wait.oneSec();
            context.startActivity(i);
        }
    }
}

Деятельность, которую я называю:

import Android.app.Activity;
import Android.os.Bundle;
import Android.telephony.TelephonyManager;
import Android.util.Log;
import Android.view.View.MeasureSpec;
import Android.view.Window;
import Android.view.WindowManager;
import Android.widget.TextView;

public class IncomingCallActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        try {
            Log.d("IncomingCallActivity: onCreate: ", "flag2");

            */ After this line, the code is not executed in Android 4.1 (Jelly bean) only/*

            // TODO Auto-generated method stub
            super.onCreate(savedInstanceState);

            getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
            getWindow().addFlags(
                    WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);

            Log.d("IncomingCallActivity: onCreate: ", "flagy");

            setContentView(R.layout.main);

            Log.d("IncomingCallActivity: onCreate: ", "flagz");

            String number = getIntent().getStringExtra(
                    TelephonyManager.EXTRA_INCOMING_NUMBER);
            TextView text = (TextView) findViewById(R.id.text);
            text.setText("Incoming call from " + number);
        } 
        catch (Exception e) {
            Log.d("Exception", e.toString());
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

После

try {
    Log.d("IncomingCallActivity: onCreate: ", "flag2");
}

Код не выполняется в Android 4.1 (Jelly Bean), но в других версиях он работает.

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

Как я могу достичь этой функциональности для приложения Android?

Вот как работает настоящий абонент:

Enter image description here

Мой настоящий вывод:

Enter image description here

Обновление 1

После награды я также не получаю то, что ищу, но вернусь ко всем; Я работаю над этим. Во всяком случае, этот код работает для большинства телефонов Android. Если кто-то собирается использовать и найти решение для него, пожалуйста, напишите здесь, чтобы каждый мог получить выгоду.

Обновление 2

Я попытался реализовать Toast в методе onReceive приемника вещания, потому что toast является нативным компонентом Android, но он также не отображается в Android 4.1 (Jelly bean).

Моя идея заключалась в том, чтобы внедрить Toast в метод onReceive приемника вещания, а затем изменить его дизайн в соответствии с нашими потребностями и настроить продолжительность отображения. Но еще одна проблема заключается в том, что findViewById не работает в приемнике вещания, поэтому я думаю, что мы должны сделать LinearLayout программно для настройки тоста.

48
Nikhil Agrawal

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

new Handler().postDelayed(new Runnable() {

     @Override
     public void run() {
         // TODO Auto-generated method stub
         Intent intent = new Intent(context, AcceptReject.class);
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         context.startActivity(intent);
     }
 }, 2000);

Я надеюсь, что это может помочь вам.

27
Hiren Dabhi

Попробуйте код перед методом super.onCreate. Я думаю, после вызова супер код пропускается. Когда-то этот вид трюков работал на меня.

9
Jashan PJ

Я только что проверил на Android 4.2 (Jelly bean) эмулятор, и он отлично работает, блокируя весь экран входящего вызова точно так же, как truecaller:

public void onReceive(Context context, Intent intent) {

    WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);

    WindowManager.LayoutParams params = new WindowManager.LayoutParams(
        LayoutParams.MATCH_PARENT,
        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 = LayoutParams.MATCH_PARENT;
    params.width = LayoutParams.MATCH_PARENT;
    params.format = PixelFormat.TRANSLUCENT;

    params.gravity = Gravity.TOP;

    LinearLayout ly = new LinearLayout(context);
    ly.setBackgroundColor(Color.RED);
    ly.setOrientation(LinearLayout.VERTICAL);

    wm.addView(ly, params);
}

В манифесте:

<receiver Android:name=""  Android:enabled="true" >
    <intent-filter Android:priority="-1">
        <action Android:name="Android.intent.action.PHONE_STATE" />
    </intent-filter>
</receiver>
9
Sam Adamsh

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

Ответ Сэма Адамса, опубликованный мной, работает для меня, хотя я вызываю код из PhoneStateListener. Кроме того, единственная реальная разница в его коде заключается в том, что я раздуваю макет:

overlay = (RelativeLayout) inflater.inflate(R.layout.overlay, null);
wm.addView(overlay, params);

Он работает как на эмуляторах, так и на HTC One S (под управлением Android 4.1.1).

Нужно иметь в виду, что вы сохраняете ссылку на добавляемый вид наложения и снова удаляете его (вызываете метод removeView () для экземпляра windowmanager), когда телефон возвращается в режим ожидания (когда слушатель получает TelephonyManager.CALL_STATE_IDLE), в противном случае Ваше наложение останется на экране.

        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    if(overlay!=null)
    {
        wm.removeView(overlay);
        overlay = null;
    }
6
bgse

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

Вы можете расположить этот вид в любом месте экрана или просто закрыть весь экран.

Вот несколько строк кода:

 _av = new ActivatorView(this);
 _avLayoutParams = new WindowManager.LayoutParams(0, 0, 0, 0,
     WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
     WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
     PixelFormat.OPAQUE);
 _avLayoutParams.screenBrightness = _fScreenBrightness = 20f;

 WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
 wm.addView(_av, _avLayoutParams);

https://bitbucket.org/gyrussolutions/yaab/src/f01cc8aff690cae1b1107287cb17835b8a3c1643/src/biz/gyrus/yaab/LightMonitorService.java?at=default#cl-338 - полный пример кода, рассмотрите его.

6
Andrey Voitenkov

Я тоже работаю над этим (я могу ошибаться, чтобы понять вас здесь). То, чего вы хотите добиться, это отобразить эту активность в Android 4.2 (Jelly bean). Я просто поместил задержку для отображения активности. Я использовал PhoneStateListener в другом классе. Я могу отображать новые действия на экране вызывающего абонента. Вот мой полный код:

Enter image description here

Файл MyBroadcastReceiver.Java

public class MyBroadcastReceiver extends BroadcastReceiver {
    static CustomPhoneStateListener phoneStateListener;
    Context context;
    Intent intent;

    @Override
    public void onReceive(Context context, Intent intent) {
        this.context = context;
        this.intent = intent;
        // TODO Auto-generated method stub

            TelephonyManager telephonyManager = (TelephonyManager) context
                    .getSystemService(Context.TELEPHONY_SERVICE);           
            phoneStateListener = new CustomPhoneStateListener(context);
            telephonyManager.listen(phoneStateListener,
                    PhoneStateListener.LISTEN_CALL_STATE);
    }
}

Файл CustomPhoneStateListener.Java

public class CustomPhoneStateListener extends PhoneStateListener {

    // private static final String TAG = "PhoneStateChanged";
    Context context; // Context to make Toast if required
    private AudioManager amanager;
    Intent i1;

    public CustomPhoneStateListener(Context context) {
        super();
        this.context = context;
        i1 = new Intent(context, YourActivity.class);       
        i1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        i1.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);

    }

    @Override
    public void onCallStateChanged(int state, String incomingNumber) {
        super.onCallStateChanged(state, incomingNumber);

        switch (state) {
        case TelephonyManager.CALL_STATE_IDLE:
            Toast.makeText(context, "Phone state Idle", Toast.LENGTH_LONG)
                    .show();

            break;
        case TelephonyManager.CALL_STATE_OFFHOOK:

            Toast.makeText(context, "Phone state Off hook", Toast.LENGTH_LONG)
                    .show();

            break;
        case TelephonyManager.CALL_STATE_RINGING:           
            try {
                Thread.sleep(3000);
                context.startActivity(i1);              
            } catch (Exception e) {
                e.getLocalizedMessage();
            }

        default:
            break;
        }
    }

и YourActivity останется тем, что вы создали ... Примечание: я сталкиваюсь с некоторыми проблемами, и в этом коде они здесь.

  1. Когда закрытый вызов является clolse (пропущенный вызов или отклонен), действие не закрывается.
  2. Я не могу нажать на «Активность» (я хочу поместить одну кнопку для своего приложения)
  3. Работает только в первый раз. Когда я звоню второй раз, мое приложение останавливается (я думаю, это потому, что активность не закрывается, когда звонок отклонен)

(Помощь принята для решения этих проблем. Спасибо. Могу помочь кому-нибудь)

ОБНОВЛЕНИЕ

ЗДЕСЬ IS ССЫЛКА НЕБОЛЬШОЙ ДЕМО КАК ДОБИТЬСЯ ЭТОГО.

  1. Когда закрытый вызов является clolse (пропущенный вызов или отклонен), действие не закрывается. - решено
  2. Я не могу нажать на кнопку «Активность» (я хочу добавить туда одну кнопку для своего приложения) - решено
  3. Работает только в первый раз. Когда я делаю вызов во второй раз, мое приложение останавливается (я думаю, это потому, что активность не закрывается, когда вызов отклонен) - решено
6
Dharmik

Мы также столкнулись с подобной проблемой, что оверлей не отображался на устройстве с блокировкой пин-кода. Решение, которое сработало для нас, ниже:

mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
    mParams = new LayoutParams(
        LayoutParams.MATCH_PARENT,
        LayoutParams.WRAP_CONTENT,
        LayoutParams.TYPE_SYSTEM_ERROR,
        LayoutParams.FLAG_NOT_FOCUSABLE,
        PixelFormat.TRANSLUCENT);

Это был LayoutParams.TYPE_SYSTEM_ERROR, который имел значение.

1
Manju Mathew

Мой метод:

  1. использовать приемник для получения событий телефонного звонка
  2. использовать сервис для наложения

    ps:wmParams.type = WindowManager.LayoutParams.TYPE_PHONE; 
    
0
user2927550

попробуй это

AlertDialog.Builder builder = new AlertDialog.Builder(context.getApplicationContext());
            LayoutInflater inflater = LayoutInflater.from(context);
            View dialogView = inflater.inflate(R.layout.caller_dialog, null);
            ImageView button = dialogView.findViewById(R.id.close_btn);
            builder.setView(dialogView);
            final AlertDialog alert = builder.create();
            alert.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
            alert.getWindow().setType(WindowManager.LayoutParams.TYPE_PHONE);
            alert.setCanceledOnTouchOutside(true);
            alert.show();
            WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
            Window window = alert.getWindow();
            window.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
            window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
            window.setGravity(Gravity.TOP);
            lp.copyFrom(window.getAttributes());
            //This makes the dialog take up the full width
            lp.width = WindowManager.LayoutParams.MATCH_PARENT;
            lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
            window.setAttributes(lp);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    //close the service and remove the from from the window
                    alert.dismiss();
                }
            });
0
Karmelina Michael

Используйте простой широковещательный приемник и поместите этот код в широковещательный приемник: 

public void onReceive(final Context context, final Intent intent) {

    Log.v(LOG_TAG, "Receieved notification about network status");
    WindowManager wm = (WindowManager) context.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.TRANSLUCENT;

    params.gravity = Gravity.TOP;

    LinearLayout ly = new LinearLayout(context);
    ly.setBackgroundColor(Color.RED);
    ly.setOrientation(LinearLayout.VERTICAL);

    wm.addView(ly, params);

}
0
Riyaz Khan
new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
        // TODO Auto-generated method stub
        Intent i = new Intent(context, CallingIncoming.class);
        i.putExtras(intent);
        i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK /*| Intent.FLAG_ACTIVITY_CLEAR_TASK*/);
        context.startActivity(i);
    }
}, 450);//It will help you to delay your screen and after it your screen will be top of default app screen
0
Amrish Kakadiya