Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement dialog like truecaller

Tags:

I am trying to implement the app similar to true caller,I am able to get the phone number when the phone rings using broadcast receiver and opening the MyCustomDialog Activity

This is my receiver class by which I am getting the Call State that the call is starts or ends. In this, I make some methods which I am using in 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);
    }
}

My 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" />

By implementing all this stuff I am getting the desired output

my receiver output on incoming call

Please guide me how to make this activity dialog dragable like the popup of the truecaller app.

I am searching for the dialog similar to this image ,

truecaller incoming screen

like image 465
Kushal Avatar asked Aug 21 '15 07:08

Kushal


People also ask

How do I show incoming call popup like Truecaller in react native?

Implementing this in react-native by registering Headless task. Registering the App as a Foreground service to run the app in the foreground. Open the App on receiving incoming calls using react-native-invoke-app. Navigate the user to Call PopupScreen and Show the user details.

Is there any alternative for Truecaller?

Whoscall is one of the best caller ID services out there and hence it is one of the best Truecaller alternatives that you can use on your Android and iOS devices. The app has been downloaded more than 65 million times and has a repository of over a billion numbers.

What is Bell cross in Truecaller?

Truecaller's Availability feature makes it possible for you to know if the person you're about to call is busy or not. For example, if you see a red bell icon next to that number it means that phone is on silent mode.


1 Answers

It is possible through OnTouchListener, Try this https://github.com/andreilisun/Swipe-To-Dismiss-Dialog The Dialog is draggable, I have changed the SwipeDimissDialog to remove dismissal of Dialog in the following class -

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);
        }
    }
}
like image 136
Yauraw Gadav Avatar answered Oct 16 '22 05:10

Yauraw Gadav