Пользовательский экран входящего/исходящего звонка в Android

Я пытаюсь реализовать пользовательский экран входящих вызовов/исходящих вызовов. Вот что я пробовал. U дал две проблемы

  • Иногда он вызывает экран ввода по умолчанию на моем телефоне, или иногда он вызывает настраиваемый экран. Я бы всегда звонил по настроенному экрану.

  • Я не могу инициировать вызовы для исходящих. настраиваемый экран просто появляется, но не вызывает никаких вызовов.

Как решить эту проблему, я не уверен, что здесь не так. Было бы здорово, если кто-то может помочь мне исправить это.

Вот что я пытаюсь:

манифеста:

<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: у него есть как входящие, так и исходящие

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(для целей пользовательского интерфейса - входящие и исходящие):

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

};

  }

Ответ 1

Для исходящих вызовов: я выполнял следующие действия, и он работает нормально. Я создал исходящий приемник со всеми разрешениями, необходимыми в манифесте.

Вызов активности после задержки с помощью обработчика.

Вот так:

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

Вы можете использовать номер телефона, чтобы отправить его новому действию.

Сообщите мне, если у вас есть вопросы!

Ответ 2

Я не могу получить экран входящего вызова... Я могу видеть только экран по умолчанию для совершения вызова, а не для приема вызова......