Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom incoming/outgoing call screen in Android

I am trying to implement custom incoming/outgoing calling screen. The following is what I have tried. U gave two problems

  1. Sometime it calls the default incoming screen on my phone or sometimes it calls the customized screen. I would the phone always call customized screen.

  2. I am not able to initiate calls for outgoing. the customized screen just comes up but doesn't make any calls.

How to solve this issue, I am not sure what is wrong here. It would be great if somebody can help me out fixing this..

Here is what I am trying:

Manifest:

<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@android:style/Theme.NoTitleBar" >
    <activity
        android:name="com.honey.ringer.MainActivity"
        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="com.honey.ringer.AcceptCall"
        android:screenOrientation="portrait"
        android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen" >
        <intent-filter>
            <action android:name="android.intent.action.ANSWER" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
    </activity>

    <receiver
        android:name="com.honey.ringer.PhoneListenerBroad">
        <intent-filter>
            <action android:name="android.intent.action.PHONE_STATE" />
            <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
        </intent-filter>
    </receiver>
</application>

BroadCastReciever: This has both incoming and outgoing

public class PhoneListenerBroad extends BroadcastReceiver
{

Context c;
private String outgoing;

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

    if (intent.getAction().equals("android.intent.action.NEW_OUTGOING_CALL")) 
    {
        outgoing = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER); 
        int state = 2;
        Intent intentPhoneCall = new Intent(c, AcceptCall.class);
        intentPhoneCall.putExtra("incomingnumber", outgoing);
        intentPhoneCall.putExtra("state", state);
        intentPhoneCall.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        c.startActivity(intentPhoneCall);
    }

    try
    {
        TelephonyManager tmgr = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        MyPhoneStateListener PhoneListener = new MyPhoneStateListener();
        tmgr.listen(PhoneListener, PhoneStateListener.LISTEN_CALL_STATE);
    }
    catch (Exception e) 
    {
        Log.e("Phone Receive Error", " " + e);
    }

}

private class MyPhoneStateListener extends PhoneStateListener
{
    public void onCallStateChanged(final int state, final String incomingNumber) 
    {
        Handler callActionHandler = new Handler();
        Runnable runRingingActivity = new Runnable() 
        {
            @Override
            public void run() 
            {
                if (state == 1)
                {
                    Intent intentPhoneCall = new Intent(c, AcceptCall.class);
                    intentPhoneCall.putExtra("incomingnumber", incomingNumber);
                    intentPhoneCall.putExtra("state", state);
                    intentPhoneCall.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    c.startActivity(intentPhoneCall);
                }
            }
        };

        if (state == 1)
        {   
            callActionHandler.postDelayed(runRingingActivity, 100);
        }

        if (state == 0) 
        {
            callActionHandler.removeCallbacks(runRingingActivity);
        }
    }
}

}

AcceptCall.java (For UI purpose - Incoming and outgoing):

 @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
 public class AcceptCall extends Activity implements OnClickListener 
 {
LinearLayout answerButton;
LinearLayout rejectButton;
LinearLayout timerLayout;

TextView contactName;
TextView contactNumber;
ImageView profile;

private String incomingnumber;
private int state;

String name = null;
String contactId = null;

InputStream photo_stream;

TextView callType;



@Override
protected void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.testactivity);

    answerButton = (LinearLayout) findViewById(R.id.callReceive);
    answerButton.setOnClickListener(this);

    rejectButton = (LinearLayout) findViewById(R.id.callReject);
    rejectButton.setOnClickListener(this);

    timerLayout = (LinearLayout) findViewById(R.id.timerLayout);

    contactName = (TextView) findViewById(R.id.contactName);
    contactNumber = (TextView) findViewById(R.id.contactNumber);

    callType = (TextView) findViewById(R.id.callType);

    timerValue = (TextView) findViewById(R.id.timerValue);

    profile  = (ImageView)findViewById(R.id.contactPhoto);     

    Bundle bundle =  getIntent().getExtras();
    if(bundle != null)
    {
        incomingnumber = bundle.getString("incomingnumber");
        state = bundle.getInt("state");
    }

    contactslookup(incomingnumber);

    contactName.setText(name);
    contactNumber.setText(incomingnumber);


    if (state == 2)
    {
        /*String uri = "tel:" + incomingnumber.trim();
        Intent intent = new Intent(Intent.ACTION_CALL);
        intent.setData(Uri.parse(uri));
        startActivity(intent);*/
    }

    PhoneStateListener phoneStateListener = new PhoneStateListener() 
    {
        @Override
        public void onCallStateChanged(int state, String incomingNumber) 
        {
            //wen ringing
            if (state == TelephonyManager.CALL_STATE_RINGING)
            {
                Log.e("CALL_STATE_RINGING","CALL_STATE_RINGING");
            } 

            //after call cut
            else if(state == TelephonyManager.CALL_STATE_IDLE)
            {
                RejectCall();
            } 

            //wen speaking / outgoing call
            else if(state == TelephonyManager.CALL_STATE_OFFHOOK)
            {
                Log.e("CALL_STATE_OFFHOOK","CALL_STATE_OFFHOOK");
            }
            super.onCallStateChanged(state, incomingNumber);
        }
    };
    TelephonyManager mgr = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
    if(mgr != null) 
    {
        mgr.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
    }
}


private void contactslookup(String number) 
{

    Log.v("ffnet", "Started uploadcontactphoto...");

    //InputStream input = null;

    // define the columns I want the query to return
    String[] projection = new String[] {ContactsContract.PhoneLookup.DISPLAY_NAME,ContactsContract.PhoneLookup._ID};

    // encode the phone number and build the filter URI
    Uri contactUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));

    // query time
    Cursor cursor = getContentResolver().query(contactUri, projection, null, null, null);

    if (cursor.moveToFirst()) 
    {
        // Get values from contacts database:
        contactId = cursor.getString(cursor.getColumnIndex(ContactsContract.PhoneLookup._ID));
        name =      cursor.getString(cursor.getColumnIndex(ContactsContract.PhoneLookup.DISPLAY_NAME));
    } 

    else 
    {
        return; // contact not found
    }


    int currentapiVersion = android.os.Build.VERSION.SDK_INT;
    if (currentapiVersion >= 14)
    {
        Uri my_contact_Uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, Long.parseLong(contactId));
        photo_stream = ContactsContract.Contacts.openContactPhotoInputStream(getContentResolver(), my_contact_Uri, true);
    }
    else
    {
        Uri my_contact_Uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, Long.parseLong(contactId));
        photo_stream = ContactsContract.Contacts.openContactPhotoInputStream(getContentResolver(), my_contact_Uri);
    }

    if(photo_stream != null) 
    {
        BufferedInputStream buf =new BufferedInputStream(photo_stream);
        Bitmap my_btmp = BitmapFactory.decodeStream(buf);
        profile.setImageBitmap(my_btmp);
    }
    else
    {
        profile.setImageResource(R.drawable.contactpic);
    }

    cursor.close();
}

@Override
public boolean onCreateOptionsMenu(Menu menu) 
{
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

@Override
public void onClick(View v) 
{
    // TODO Auto-generated method stub
    if(v.getId() == answerButton.getId())
    {
        timerLayout.setVisibility(0);

        startTime = SystemClock.uptimeMillis();
        customHandler.postDelayed(updateTimerThread, 0);

        callType.clearAnimation();

        // Simulate a press of the headset button to pick up the call
        Intent buttonDown = new Intent(Intent.ACTION_MEDIA_BUTTON);     
        buttonDown.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_HEADSETHOOK));
        this.sendOrderedBroadcast(buttonDown, "android.permission.CALL_PRIVILEGED");

        // froyo and beyond trigger on buttonUp instead of buttonDown
        Intent buttonUp = new Intent(Intent.ACTION_MEDIA_BUTTON);       
        buttonUp.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK));
        this.sendOrderedBroadcast(buttonUp, "android.permission.CALL_PRIVILEGED"); 
    }

    if(v.getId() == rejectButton.getId())
    {
        RejectCall();
    }

}

private void RejectCall() 
{
    TelephonyManager telephony = (TelephonyManager)this.getSystemService(Context.TELEPHONY_SERVICE);

    try {
        // Java reflection to gain access to TelephonyManager's
        // ITelephony getter
        Class c = Class.forName(telephony.getClass().getName());
        Method m = c.getDeclaredMethod("getITelephony");
        m.setAccessible(true);
        com.android.internal.telephony.ITelephony telephonyService = (ITelephony) m.invoke(telephony);
        telephonyService.endCall();
        finish();

        timeSwapBuff += timeInMilliseconds;
        customHandler.removeCallbacks(updateTimerThread);
    }
    catch (Exception e) 
    {
        e.printStackTrace();
        Log.e("Error", "FATAL ERROR: could not connect to telephony subsystem");
        Log.e("Error", "Exception object: " + e);
    }
}

private Runnable updateTimerThread = new Runnable() 
{

    public void run() 
    {
        timeInMilliseconds = SystemClock.uptimeMillis() - startTime;
        updatedTime = timeSwapBuff + timeInMilliseconds;
        int secs = (int) (updatedTime / 1000);
        int mins = secs / 60;
        int hours = mins / 60;
        secs = secs % 60;
        int milliseconds = (int) (updatedTime % 1000);
        timerValue.setText(""+ hours + ":" + String.format("%02d", mins) + ":"
                + String.format("%02d", secs));
        customHandler.postDelayed(this, 0);
    }

};

  }
like image 906
TheDevMan Avatar asked Mar 14 '14 10:03

TheDevMan


People also ask

Can you change incoming call screen on Android?

To enable a template to replace your caller screen, tap on the + sign at the bottom as shown in the picture below. After you tap on the + sign, the caller screen template will show you a preview. This is exactly what your caller screen will look like when you get a call. You've two options on this screen.

Can you customize call screening?

In all cases, you have two choices: you can choose to have the phone ring and then manually decide whether you want to screen the call or not, or you can let Google automatically screen the call and decline it if it's a robocall.

How to set video pop-up for incoming calls on Android?

You can follow these steps to set the video pop-up style for incoming calls on your Android device: Go to “ Home Screen.” Click on the “ Phone Dialer” icon. Open the screen for “ Mass Response.” Tap on the button for “Settings ” (you’ll find it on the screen’s lower right corner). Open “ Popup Menu.” Tap on “ Call Settings ” screen and open it.

How do I change the status of incoming calls on Android?

Tap on “ Call Settings ” screen and open it. Scroll down and click on “ Other Call Settings.” Check the incoming calls screen-style status and confirm that it’s “ Classic.” To change it, click on “ Classic”; this opens up the prompt for “ Current Status .” Select “ Classic” and enable it.

How do I get my Android phone to recognize incoming calls?

This instantly takes you back to the screen for “Call Settings.” Change the style for “ incoming calls ” to “ Full-screen Caller Photo.” Now, call your Android device; your caller’s screen-style photo will display. Finally, “ Save” and “ activate” the contact on your device. Voila! You’re done; it’s now possible to recognize callers fantastically.

How do I Turn on classic call status on Android?

Check the incoming calls screen-style status and confirm that it’s “ Classic.” To change it, click on “ Classic”; this opens up the prompt for “ Current Status .” Select “ Classic” and enable it. This instantly takes you back to the screen for “Call Settings.”


1 Answers

For outgoing calls: I did the following as a work around and it is working fine. I created an outgoing receiver with all permissions required in manifest..

Called the Activity after a delay by using a handler.

Like this:

@Override
public void onReceive(Context context, Intent intent) 
{
    c = context;
    setResultData(null);
    phonenumber = getResultData();
    if (phonenumber == null)
    {
        phonenumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
    }
    setResultData(phonenumber);
    callActionHandler.postDelayed(runRingingActivity, 1000);
}


Handler callActionHandler = new Handler();
Runnable runRingingActivity = new Runnable() 
{
    @Override
    public void run() 
    {

        Intent intentPhoneCall = new Intent(c, OutgoingCallActivity.class);
        intentPhoneCall.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        intentPhoneCall.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        c.startActivity(intentPhoneCall);
    }
};

You can use the phone number to send it to the new activity.

Let me know if you have any questions!

like image 170
TheDevMan Avatar answered Nov 03 '22 00:11

TheDevMan