title: Custom incoming/outgoing call screen in Android
body: <p>I am trying to implement custom incoming/outgoing calling screen. The following is what I have tried. U gave two problems </p>
  
  <ol>
  <li><p>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.</p></li>
  <li><p>I am not able to initiate calls for outgoing. the customized screen just comes up but doesn't make any calls.</p></li>
  </ol>
  
  <p>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..</p>
  
  <p>Here is what I am trying:</p>
  
  <p><strong>Manifest:</strong></p>
  
  <pre><code>&lt;uses-permission android:name="android.permission.READ_PHONE_STATE" /&gt;
  &lt;uses-permission android:name="android.permission.READ_CONTACTS" /&gt;
  &lt;uses-permission android:name="android.permission.CALL_PHONE" /&gt;
  &lt;uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" /&gt;
  &lt;uses-permission android:name="android.permission.MODIFY_PHONE_STATE" /&gt;
  
  &lt;application
      android:allowBackup="true"
      android:icon="@drawable/ic_launcher"
      android:label="@string/app_name"
      android:theme="@android:style/Theme.NoTitleBar" &gt;
      &lt;activity
          android:name="com.honey.ringer.MainActivity"
          android:label="@string/app_name" &gt;
          &lt;intent-filter&gt;
              &lt;action android:name="android.intent.action.MAIN" /&gt;
  
              &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
          &lt;/intent-filter&gt;
      &lt;/activity&gt;
      &lt;activity
          android:name="com.honey.ringer.AcceptCall"
          android:screenOrientation="portrait"
          android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen" &gt;
          &lt;intent-filter&gt;
              &lt;action android:name="android.intent.action.ANSWER" /&gt;
              &lt;category android:name="android.intent.category.DEFAULT" /&gt;
          &lt;/intent-filter&gt;
      &lt;/activity&gt;
  
      &lt;receiver
          android:name="com.honey.ringer.PhoneListenerBroad"&gt;
          &lt;intent-filter&gt;
              &lt;action android:name="android.intent.action.PHONE_STATE" /&gt;
              &lt;action android:name="android.intent.action.NEW_OUTGOING_CALL" /&gt;
          &lt;/intent-filter&gt;
      &lt;/receiver&gt;
  &lt;/application&gt;
  </code></pre>
  
  <p></p>
  
  <p><strong>BroadCastReciever: This has both incoming and outgoing</strong></p>
  
  <pre><code>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);
          }
      }
  }
  </code></pre>
  
  <p>}</p>
  
  <p><strong>AcceptCall.java (For UI purpose - Incoming and outgoing):</strong></p>
  
  <pre><code> @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 &gt;= 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);
      }
  
  };
  
    }
  </code></pre>