web-dev-qa-db-fra.com

Fenêtre contextuelle sur l'écran des appels entrants natifs Android, comme une application Android

Je développe un récepteur de diffusion pour les appels entrants dans Android et lors de la réception d'appels entrants, je souhaite faire apparaître une fenêtre contextuelle sur l'écran des appels entrants natifs.

J'ai complété ce code. Mais maintenant, le problème est que dans le l'API Android 4.1 (Jelly Bean) de niveau 17 lorsqu'un téléphone sonne, le PHONE_STATE se présente sous la forme OFF HOOK et, si j'appelle une activité, elle est appelée, mais le code correspondant ne soit pas exécuté. Je liste le code:

Mon récepteur de diffusion

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

Une activité que j'appelle:

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

Après

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

Le code ne s'exécute pas dans Android 4.1 (Jelly Bean), mais dans d'autres versions, il fonctionne.

J'ai essayé presque tous les moyens que je peux faire. Ce code affiche une activité translucide sur l'écran d'appel natif et ne bloque pas les contrôles en arrière-plan, comme pour prendre le téléphone. Mais je le veux comme un vrai appelant. J'ai joint un instantané indiquant comment le véritable appelant affiche une fenêtre sur l'écran des appels entrants.

Comment puis-je obtenir cette fonctionnalité pour une application Android?

Voici comment fonctionne un véritable appelant:

Enter image description here

Ma sortie actuelle:

Enter image description here

Mise à jour 1

Après la prime, je ne reçois pas exactement ce que je cherche, mais je reviendrai à tous. Je travaille dessus. Quoi qu'il en soit, ce code fonctionne pour la plupart des téléphones Android. Si quelqu'un veut utiliser et trouver la solution, écrivez ici pour que tout le monde puisse en tirer profit.

Mise à jour 2

J'ai essayé d'implémenter Toast dans la méthode onReceive du récepteur de diffusion, car toast est un composant natif d'Android, mais il ne s'affiche pas non plus dans Android 4.1 (Jelly Bean).

Mon idée était d'implémenter Toast dans la méthode onReceive du récepteur de diffusion, puis de modifier sa conception en fonction de nos besoins et d'ajuster sa durée d'affichage. Mais un autre problème est que findViewById ne fonctionne pas dans le récepteur de diffusion. Je pense donc que nous devons créer un LinearLayout par programme pour personnaliser le pain grillé.

48
Nikhil Agrawal

Je ne suis pas sûr que votre interface graphique personnalisée sera toujours au-dessus de celle par défaut, car le récepteur de diffusion système et votre récepteur essaient tous deux d'afficher leur interface graphique en haut de l'écran. Nous ne savons pas lequel est appelé en premier, mais la tâche la plus difficile pour afficher votre interface graphique en haut de l'écran est lorsque le téléphone sonne, appelez votre activité après 1 à 2 seconde (s).

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

J'espère que cela peut vous aider.

27
Hiren Dabhi

Essayez le code avant la méthode super.onCreate. Je pense qu'après avoir appelé le super, le code est sauté. Parfois, ce type de ruse fonctionnait pour moi.

9
Jashan PJ

Je viens de tester sur Android 4.2 (Jelly bean) emulator, et cela fonctionne parfaitement en bloquant l’écran d’appel entrant dans son intégralité, comme à l’avance:

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

Dans le manifeste:

<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

J'essaie quelque chose de similaire, en ajoutant un bouton supplémentaire à l'écran des appels entrants.

La réponse affichée par Sam Adams fonctionne pour moi, bien que j'appelle le code à partir d'un PhoneStateListener. En dehors de cela, la seule différence réelle par rapport à son code est que je gonfle une mise en page:

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

Il fonctionne sur les émulateurs ainsi que sur un HTC One S (sous Android 4.1.1).

N'oubliez pas de garder une référence à la vue de superposition que vous ajoutez et de la supprimer à nouveau (appelez removeView () sur l'instance de windowmanager) lorsque le téléphone redevient inactif (lorsque l'écouteur obtient TelephonyManager.CALL_STATE_IDLE), sinon votre incrustation restera à l'écran.

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

Je pense que vous ne devriez pas commencer l'activité pour atteindre le résultat décrit. Vous avez besoin d'une vue séparée dans laquelle LayoutParams.TYPE_SYSTEM_OVERLAY est défini dans ses paramètres de présentation.

Vous pouvez positionner cette vue où vous voulez sur l'écran, ou simplement couvrir tout l'écran.

Voici quelques lignes de code:

 _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 - le mot de passe complet.

6
Andrey Voitenkov

Je travaille aussi dessus (j'ai peut-être tort de vous comprendre ici). Ce que vous voulez réaliser, c'est afficher cette activité dans Android 4.2 (Jelly Bean). Je viens de placer un délai pour afficher l'activité. J'ai utilisé PhoneStateListener dans différentes classes. Je suis capable d'afficher une nouvelle activité sur l'écran de l'appelant. Voici mon code complet:

Enter image description here

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

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

et Votre activité restera telle que vous l'avez créée .... Note: je suis confronté à des problèmes également dans ce code, ils sont ici.

  1. Lorsque l'appel est fermé (appel manqué ou rejeté), l'activité n'est pas fermée.
  2. Je ne peux pas cliquer sur Activité (je veux y mettre un bouton pour mon application)
  3. Cela ne fonctionne que la première fois. Lorsque je passe un appel une deuxième fois, mon application s’arrête (je pense que c’est parce que Activity n’est pas fermée lorsque l’appel est rejeté)

(Aide acceptée pour ces problèmes. Merci. Pourrait aider quelqu'un)

METTRE &AGRAVE; JOUR

ICI IS LIEN DE PETITE DEMO COMMENT Y ARRIVER.

  1. Lorsque l'appel est fermé (appel manqué ou rejeté), l'activité n'est pas fermée. - RESOLU
  2. Je ne peux pas cliquer sur Activité (je veux y mettre un bouton pour mon application) - Résolu
  3. Cela ne fonctionne que la première fois. Lorsque je passe un appel une deuxième fois, mon application s’arrête (je pense que c’est parce que Activity n’est pas fermée lorsque l’appel est rejeté) - RESOLU
6
Dharmik

Nous étions également confrontés à un problème similaire, à savoir que la superposition ne soit pas affichée sur un périphérique avec verrouillage des broches. La solution qui a fonctionné pour nous est la suivante:

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

C'est LayoutParams.TYPE_SYSTEM_ERROR qui a fait la différence.

1
Manju Mathew

Ma méthode:

  1. utiliser le récepteur pour recevoir les événements d'un appel téléphonique
  2. utiliser le service pour faire la superposition

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

essaye ça

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

Utilisez un simple récepteur de diffusion et mettez ce code dans le récepteur de diffusion: 

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