Android手机通话界面-更改

Android手机通话界面-更改,android,user-interface,phone-call,Android,User Interface,Phone Call,如何更改电话用户界面?就像我有自己的拨号器布局和联系人布局,但我如何更改呼叫用户界面。那么,当通话开始时,我可以移除扬声器按钮吗 以下是我创建的拨号器场景: 但我不知道如何编辑此屏幕: 编辑:我已经构建了UI,我只是无法在通话中显示它 以下是更简单版本的代码: public class MainActivity extends Activity { private Button callBtn; private Button dialBtn; private EditText number;

如何更改电话用户界面?就像我有自己的拨号器布局和联系人布局,但我如何更改呼叫用户界面。那么,当通话开始时,我可以移除扬声器按钮吗

以下是我创建的拨号器场景:

但我不知道如何编辑此屏幕:

编辑:我已经构建了UI,我只是无法在通话中显示它

以下是更简单版本的代码:

public class MainActivity extends Activity {

private Button callBtn;
private Button dialBtn;
private EditText number;

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

    number = (EditText) findViewById(R.id.phoneNumber);
    callBtn = (Button) findViewById(R.id.call);
    dialBtn = (Button) findViewById(R.id.dial);

    // add PhoneStateListener for monitoring
    MyPhoneListener phoneListener = new MyPhoneListener();
    TelephonyManager telephonyManager = 
        (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
    // receive notifications of telephony state changes 
    telephonyManager.listen(phoneListener,PhoneStateListener.LISTEN_CALL_STATE);

    callBtn.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            try {
                // set the data
                String uri = "tel:"+number.getText().toString();
                Intent callIntent = new Intent(Intent.ACTION_CALL, Uri.parse(uri));

                startActivity(callIntent);
            }catch(Exception e) {
                Toast.makeText(getApplicationContext(),"Your call has failed...",
                    Toast.LENGTH_LONG).show();
                e.printStackTrace();
            }
        }
    });

    dialBtn.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            try {
                String uri = "tel:"+number.getText().toString();
                Intent dialIntent = new Intent(Intent.ACTION_DIAL, Uri.parse(uri));

                startActivity(dialIntent);
            }catch(Exception e) {
                Toast.makeText(getApplicationContext(),"Your call has failed...",
                    Toast.LENGTH_LONG).show();
                e.printStackTrace();
            }
        }
    });
}

private class MyPhoneListener extends PhoneStateListener {

    private boolean onCall = false;

    @Override
    public void onCallStateChanged(int state, String incomingNumber) {

        switch (state) {
        case TelephonyManager.CALL_STATE_RINGING:
            // phone ringing...
            Toast.makeText(MainActivity.this, incomingNumber + " calls you", 
                    Toast.LENGTH_LONG).show();
            break;

        case TelephonyManager.CALL_STATE_OFFHOOK:
            // one call exists that is dialing, active, or on hold
            Toast.makeText(MainActivity.this, "on call...", 
                    Toast.LENGTH_LONG).show();
            //because user answers the incoming call
            onCall = true;
            break;

        case TelephonyManager.CALL_STATE_IDLE:
            // in initialization of the class and at the end of phone call 

            // detect flag from CALL_STATE_OFFHOOK
            if (onCall == true) {
                Toast.makeText(MainActivity.this, "restart app after call", 
                        Toast.LENGTH_LONG).show();

                // restart our application
                Intent restart = getBaseContext().getPackageManager().
                    getLaunchIntentForPackage(getBaseContext().getPackageName());
                restart.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                startActivity(restart);

                onCall = false;
            }
            break;
        default:
            break;
        }

    }
}
}

谢谢

构建您自己的拨号器用户界面。退房
您将需要一个活动来处理意图,然后显示自定义UI是您的业务。

在清单中添加调用权限

<uses-permission android:name="android.permission.CALL_PHONE" />

然后需要检查呼叫按钮是否按下。用于以下目的过滤器

<intent-filter>
    <action android:name="android.intent.action.CALL_BUTTON" />
    <category android:name="android.intent.category.DEFAULT" />
</intent-filter>

当启动UI时

<intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <action android:name="android.intent.action.DIAL" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="tel" />
</intent-filter>

这意味着您在清单中的调用活动如下

<activity
        android:name="com.example.MainActivity"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>

        <!-- open activity when establishing a call -->
        <intent-filter>
            <action android:name="android.intent.action.CALL_PRIVILEGED" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:scheme="tel" />
        </intent-filter>

    </activity>

编辑: 实际上api 23已经发布了,请检查。请记住,某些设备可能不支持此功能

预览:

无法更改实际通话视图(通话过程中看到的内容)

更具体地说,android的某些部分无法被覆盖, 安卓有他的核心,作为开发者,我们对此的访问是有限的 核心。在您的情况下,您可以覆盖拨号器,但您不能 覆盖实际电话通话视图

在android团队决定分享之前,你不能做任何事情 这是我们(开发人员)的核心功能


由于API 23,这是可能的,请参见arekolek

Kotlin版本:

Java版本:

编辑

根据推荐,下面是最简单的java版本

下面显示了清单,需要
意图过滤器

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.aliton.customphonecall">

    <uses-permission android:name="android.permission.CALL_PHONE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".DialerActivity" >
            <intent-filter>

                <!-- Handle links from other applications -->
                <action android:name="android.intent.action.VIEW" />
                <action android:name="android.intent.action.DIAL" />
                <!-- Populate the system chooser -->
                <category android:name="android.intent.category.DEFAULT" />
                <!-- Handle links in browsers -->
                <category android:name="android.intent.category.BROWSABLE" />

                <data android:scheme="tel" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.DIAL" />

                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>

        <service
            android:name=".CallService"
            android:permission="android.permission.BIND_INCALL_SERVICE">
            <meta-data
                android:name="android.telecom.IN_CALL_SERVICE_UI"
                android:value="true" />

            <intent-filter>
                <action android:name="android.telecom.InCallService" />
            </intent-filter>
        </service>

        <activity android:name=".CallActivity"></activity>
    </application>

</manifest>
下面是如何实现
InCallService
来管理呼叫

public class CallService extends InCallService {

    OngoingCallObject ongoingCallObject;

    @Override
    public void onCallAdded(Call call) {
        super.onCallAdded(call);
        new OngoingCallObject().setCall(call);

        //Intent CallAct = new Intent(this, CallActivity.class);
        //startActivity(CallAct);

        CallActivity.start(this, call);
    }

    @Override
    public void onCallRemoved(Call call) {
        super.onCallRemoved(call);
        new OngoingCallObject().setCall(null);
    }

}
下面是对象的实现方式

public class OngoingCallObject {

    private static Call call;

    private Object callback = new Callback() {
        @Override
        public void onStateChanged(Call call, int state) {
            super.onStateChanged(call, state);
            Log.i("debinf OngoingObj", "state is "+state);
        }
    };

    public void setCall(Call call) {
        if (this.call != null) {
            this.call.unregisterCallback((Call.Callback)callback);
        }

        if (call != null) {
            call.registerCallback((Call.Callback)callback);
            Log.i("debinf OngoingObj", "call.getState() is "+call.getState());
        }

        this.call = call;
    }

    public void answer() {
        //assert this.call != null;
        if (this.call != null) {
            this.call.answer(VideoProfile.STATE_AUDIO_ONLY);
        }
    }

    public void hangup() {
        //assert this.call != null;
        if (this.call != null) {
            this.call.disconnect();
        }
    }
}
最后是启动UI的
CallActivity

public class DialerActivity extends AppCompatActivity {

    private static final int REQUEST_CALL_PHONE = 10;

    EditText phoneNumber;

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

        phoneNumber = (EditText) findViewById(R.id.etNumber);
        Button bCall = (Button) findViewById(R.id.btnCall);

        offerReplacingDefaultDialer();

        bCall.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                makeCall();
            }
        });
    }

    private void makeCall() {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED) {
            Uri uri = Uri.parse("tel:"+phoneNumber.getText().toString().trim());
            Intent Call = new Intent(Intent.ACTION_CALL, uri);
            //Toast.makeText(this, "Entered makeCall()", Toast.LENGTH_SHORT).show();
            Log.i("debinf Dialer", "Entered makeCall()");
            startActivity(Call);

        } else {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CALL_PHONE}, REQUEST_CALL_PHONE);
        }
    }

    private void offerReplacingDefaultDialer() {
        if (getSystemService(TelecomManager.class).getDefaultDialerPackage() != getPackageName()) {
            Intent ChangeDialer = new Intent(TelecomManager.ACTION_CHANGE_DEFAULT_DIALER);
            ChangeDialer.putExtra(TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME, getPackageName());
            startActivity(ChangeDialer);
        }

    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        if (requestCode == REQUEST_CALL_PHONE) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                makeCall();
            } else {
                Toast.makeText(this, "calling permission denied", Toast.LENGTH_LONG).show();
            }
            //return;
        }
    }

}
public class CallActivity extends AppCompatActivity {

    TextView callInfo;
    Button answer, hangup;

    private String number;
    private OngoingCallObject ongoingCall;

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

        ongoingCall = new OngoingCallObject();

        answer = (Button) findViewById(R.id.answer);
        hangup = (Button) findViewById(R.id.hangup);
        callInfo = (TextView) findViewById(R.id.callInfo);

        number = Objects.requireNonNull(getIntent().getData().getSchemeSpecificPart());

        callInfo.setText("Calling number : "+number);

        answer.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //Toast.makeText(CallActivity.this, "Answer button", Toast.LENGTH_SHORT).show();
                ongoingCall.answer();
            }
        });

        hangup.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ongoingCall.hangup();
            }
        });


    }

    public static void start(Context context, Call call) {
        Intent intent = new Intent(context, CallActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setData(call.getDetails().getHandle());
        context.startActivity(intent);
    }

}
以下是
DialerActivity
xml
activity\u dialer.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".DialerActivity">

    <EditText
        android:id="@+id/etNumber"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Tel number"/>

    <Button
        android:id="@+id/btnCall"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:text="CallActivity"
        android:layout_below="@+id/etNumber" />

</RelativeLayout>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".CallActivity">

    <TextView
        android:id="@+id/callInfo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.3"
        tools:text="Hello World!" />

    <Button
        android:id="@+id/answer"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Answer"
        app:layout_constraintBaseline_toBaselineOf="@+id/hangup"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/hangup" />

    <Button
        android:id="@+id/hangup"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hang up"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/answer"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/callInfo" />


</android.support.constraint.ConstraintLayout>

我希望有帮助

建立你自己的拨号接口我建立的用户界面,但我如何使它显示在通话中?你解决了吗?有一个代码,但它是用一种我不知道如何将其翻译成普通java(Android Studio)的语言编写的。如果你遵循这个链接,它会告诉你如何将意图重新定向到你的应用程序请更具描述性,也许会告诉他可以做什么,因为他想要的不起作用,谢谢。Ash Patel问“我就是不能让它在通话中显示出来!答案是:不,你不能,因为没有人能!是的,在投票之前,阅读我的答案,最后是“你不能做任何事情,直到android团队决定与我们(开发者)共享这个核心功能。”。“因此,基本上api是可以预测的,它在小米设备上不起作用。i、 e.呼叫服务在呼叫过程中不调用。我使用的是适当的级别,这就是为什么它除了小米设备外都能正常工作。对于某些设备+1不支持此功能,请务必检查如下品牌:排除Xiomi,这也需要在华为进行测试。