web-dev-qa-db-fra.com

Comment implémenter un dialogue comme truecaller

J'essaie d'implémenter l'application de la même manière que l'appelant réel. Je peux obtenir le numéro de téléphone lorsque le téléphone sonne à l'aide du récepteur de radiodiffusion et en ouvrant l'activité MyCustomDialog.

C’est ma classe de récepteur par laquelle je reçois l’état d’appel indiquant que l’appel commence ou se termine. En cela, je fais quelques méthodes que j'utilise dans CallReceiver.Java

PhonecallReceiver.Java

import Android.content.BroadcastReceiver;
import Android.content.Context;
import Android.content.Intent;
import Android.telephony.TelephonyManager;
import Java.util.Date;

public abstract class PhonecallReceiver extends BroadcastReceiver
{
    private static int lastState = TelephonyManager.CALL_STATE_IDLE;
    private static Date callStartTime;
    private static boolean isIncoming;
    private static String savedNumber;

    @Override
    public void onReceive(Context context, Intent intent)
    {
    try
    {
        if (intent.getAction().equals("Android.intent.action.NEW_OUTGOING_CALL"))
        {
            savedNumber = intent.getExtras().getString("Android.intent.extra.PHONE_NUMBER");
        }
        else
        {
            String stateStr = intent.getExtras().getString(TelephonyManager.EXTRA_STATE);
            String number = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
            int state = 0;
            if(stateStr.equals(TelephonyManager.EXTRA_STATE_IDLE))
            {
                state = TelephonyManager.CALL_STATE_IDLE;
            }
            else if(stateStr.equals(TelephonyManager.EXTRA_STATE_OFFHOOK))
            {
                state = TelephonyManager.CALL_STATE_OFFHOOK;
            }
            else if(stateStr.equals(TelephonyManager.EXTRA_STATE_RINGING))
            {
                state = TelephonyManager.CALL_STATE_RINGING;
            }

            onCallStateChanged(context, state, number);
        }
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }
}

    //Derived classes should override these to respond to specific events of interest
    protected void onIncomingCallStarted(Context ctx, String number, Date start){}
    protected void onIncomingCallEnded(Context ctx, String number, Date start, Date end){}

    public void onCallStateChanged(Context context, int state, String number)
    {
        if(lastState == state)
        {
            //No change, debounce extras
            return;
        }
        switch (state)
        {
            case TelephonyManager.CALL_STATE_RINGING:
                isIncoming = true;
                callStartTime = new Date();
                savedNumber = number;
                onIncomingCallStarted(context, number, callStartTime);
                break;

            case TelephonyManager.CALL_STATE_OFFHOOK:
                if (isIncoming)
                {
                    onIncomingCallEnded(context,savedNumber,callStartTime,new Date());
                }

            case TelephonyManager.CALL_STATE_IDLE:
                if(isIncoming)
                {
                    onIncomingCallEnded(context, savedNumber, callStartTime, new Date());
                }
        }
        lastState = state;
    }
}

CallReceiver.Java

import Android.app.Activity;
import Android.app.Dialog;
import Android.app.Notification;
import Android.content.ComponentName;
import Android.content.Context;
import Android.content.Intent;
import Android.graphics.drawable.ColorDrawable;
import Android.view.LayoutInflater;
import Android.view.View;
import Android.view.Window;
import Android.widget.Button;
import Android.widget.Toast;
import Android.os.Handler;
import Java.util.Date;

import dootam.dspl.com.lawyercasecall.R;

public class CallReceiver extends PhonecallReceiver
{
    Context context;

    @Override
    protected void onIncomingCallStarted(final Context ctx, String number, Date start)
    {
        Toast.makeText(ctx,"Kushal Incoming Call"+ number,Toast.LENGTH_LONG).show();

        context =   ctx;

        final Intent intent = new Intent(context, MyCustomDialog.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        intent.putExtra("phone_no",number);

        new Handler().postDelayed(new Runnable()
        {
            @Override
            public void run()
            {
                context.startActivity(intent);
            }
        },2000);

//        MyCus/*tomDialog dialog   =   new MyCustomDialog(context);
//        dialog.*/show();
    }

    @Override
    protected void onIncomingCallEnded(Context ctx, String number, Date start, Date end)
    {
        Toast.makeText(ctx,"Bye Bye"+ number,Toast.LENGTH_LONG).show();
    }
}

MyCustomDialog.Java

import Android.app.Activity;
import Android.os.Bundle;
import Android.util.Log;
import Android.view.View;
import Android.view.Window;
import Android.widget.Button;
import Android.widget.TextView;
import dootam.dspl.com.lawyercasecall.R;

public class MyCustomDialog extends Activity
{
    TextView tv_client;
    String phone_no;
    Button dialog_ok;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        try
        {
            requestWindowFeature(Window.FEATURE_NO_TITLE);
            this.setFinishOnTouchOutside(false);
            super.onCreate(savedInstanceState);
            setContentView(R.layout.dialog);
            initializeContent();

            /*WindowManager.LayoutParams params = getWindow().getAttributes();
            params.x = -100;
            params.height = 70;
            params.width = 1000;
            params.y = -50;

            this.getWindow().setAttributes(params);*/

            phone_no    =   getIntent().getExtras().getString("phone_no");
            tv_client.setText(""+phone_no +" is calling you");

            dialog_ok.setOnClickListener(new View.OnClickListener()
            {
                @Override
               public void onClick(View v)
                {
                    MyCustomDialog.this.finish();
//                    this.setFinishOnTouchOutside(false);
                    System.exit(0);
                }
            });
        }
        catch (Exception e)
        {
            Log.d("Exception", e.toString());
            e.printStackTrace();
        }
    }

    private void initializeContent()
    {
        tv_client   = (TextView) findViewById(R.id.tv_client);
        dialog_ok   = (Button) findViewById(R.id.dialog_ok);
    }
}

Mon AndroidManifest.xml

 <application
        Android:allowBackup="true"
        Android:icon="@mipmap/ic_launcher"
        Android:label="@string/app_name"
        Android:theme="@style/AppTheme" >
        <activity
            Android:name=".AddCasesActivity"
            Android:label="@string/app_name" >
            <intent-filter>
                <action Android:name="Android.intent.action.MAIN" />

                <category Android:name="Android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity Android:name=".receiver.MyCustomDialog"
                  Android:theme="@Android:style/Theme.Dialog"
                  Android:noHistory="true"
            />


        <receiver Android:name=".receiver.CallReceiver" >
            <intent-filter>
                <action Android:name="Android.intent.action.PHONE_STATE" />
            </intent-filter>
            <intent-filter>
                <action Android:name="Android.intent.action.NEW_OUTGOING_CALL" />
            </intent-filter>
        </receiver>

    </application>

    <uses-permission Android:name="Android.permission.READ_PHONE_STATE" />
    <uses-permission Android:name="Android.permission.PROCESS_OUTGOING_CALLS"/>
    <uses-permission Android:name="Android.permission.MODIFY_PHONE_STATE" tools:ignore="ProtectedPermissions"/>
    <uses-permission Android:name="Android.permission.SYSTEM_ALERT_WINDOW" />

En mettant en oeuvre tout ça, j'obtiens le résultat souhaité

 my receiver output on incoming call

S'il vous plaît, guidez-moi sur la manière de rendre cette boîte de dialogue glissable comme le popup de l'application TrueCaller.

Je cherche un dialogue similaire à cette image,

 truecaller incoming screen

15
Kushal

Il est possible via OnTouchListener, essayez ceci https://github.com/andreilisun/Swipe-To-Dismiss-Dialog Le dialogue est déplaçable, j'ai modifié le SwipeDimissDialog pour supprimer le renvoi de Dialog dans la classe suivante -

public class SwipeDismissDialog extends FrameLayout {

    private final Params params;
    private View dialog;

    protected SwipeDismissDialog(@NonNull Context context, Params params) {
        super(context);
        this.params = params;
        init();
    }

    private void init() {
        setOnClickListener(overlayClickListener);
        setBackgroundColor(params.overlayColor);
        dialog = params.view;
        if (dialog == null) {
            dialog = LayoutInflater.from(getContext()).inflate(params.layoutRes, this, false);
        }
        LayoutParams layoutParams = (LayoutParams) dialog.getLayoutParams();
        if (layoutParams == null) {
            layoutParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.CENTER);
        } else {
            layoutParams.gravity = Gravity.CENTER;
        }
        dialog.setOnTouchListener(touchListener);
        addView(dialog, layoutParams);
    }

    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        if (event.getAction() == KeyEvent.ACTION_DOWN
                && event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
            cancel();
            return true;
        }
        return false;
    }

    public SwipeDismissDialog show() {
        WindowManager windowManager = (WindowManager)
                getContext().getSystemService(Context.WINDOW_SERVICE);
        WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
        layoutParams.height = WindowManager.LayoutParams.MATCH_PARENT;
        layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
        layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION;
        layoutParams.format = PixelFormat.TRANSLUCENT;
        windowManager.addView(this, layoutParams);
        return this;
    }

    public void cancel() {
        if (params.cancelListener != null) {
            params.cancelListener.onCancel(dialog);
        }
        if (params.dismissOnCancel) {
            dismiss();
        }
    }

    public void dismiss() {
        dialog.setOnTouchListener(null);
        removeView(dialog);
        WindowManager windowManager = (WindowManager)
                getContext().getSystemService(Context.WINDOW_SERVICE);
        windowManager.removeViewImmediate(this);
    }

    private void dismiss(SwipeDismissDirection direction) {
        if (params.swipeDismissListener != null) {
            params.swipeDismissListener.onSwipeDismiss(this, direction);
        }
        dismiss();
    }

    private final OnTouchListener touchListener = new OnTouchListener() {

        private float initCenterX;
        private float lastEventY;
        private float lastEventX;
        private float initY;
        private float initX;

        public boolean onTouch(View view, MotionEvent motionEvent) {
            /*Fling detected*/

            int action = motionEvent.getAction();
            switch (action) {
                case MotionEvent.ACTION_DOWN: {
                    initX = view.getX();
                    initY = view.getY();
                    lastEventX = motionEvent.getRawX();
                    lastEventY = motionEvent.getRawY();
                    initCenterX = initX + view.getWidth() / 2;
                    break;
                }

                case MotionEvent.ACTION_MOVE: {
                    float eventX = motionEvent.getRawX();
                    float eventY = motionEvent.getRawY();
                    float eventDx = eventX - lastEventX;
                    float eventDy = eventY - lastEventY;
                    float centerX = view.getX() + eventDx + view.getWidth() / 2;
                    float centerDx = centerX - initCenterX;
                    view.setX(view.getX() + eventDx);
                    view.setY(view.getY() + eventDy);
                    //view.invalidate();
                    lastEventX = eventX;
                    lastEventY = eventY;
                    break;
                }

            }
            return true;
        }
    };

    private final OnClickListener overlayClickListener = new OnClickListener() {
        @Override
        public void onClick(View v) {
            cancel();
        }
    };


    public static class Builder {

        private final Params params;
        private final Context context;

        public Builder(Context context) {
            this.context = context;
            this.params = new Params();
        }

        public Builder setView(@NonNull View view) {
            params.view = view;
            params.layoutRes = 0;
            return this;
        }

        public Builder setLayoutResId(@LayoutRes int layoutResId) {
            params.layoutRes = layoutResId;
            params.view = null;
            return this;
        }

        public SwipeDismissDialog build() {
            if (params.view == null && params.layoutRes == 0) {
                throw new IllegalStateException("view should be set with setView(View view) " +
                        "or with setLayoutResId(int layoutResId)");
            }
            return new SwipeDismissDialog(context, params);
        }
    }
}
1
Gauraw Yadav