您当前的位置: 首页 > 学无止境 > 心得笔记 网站首页心得笔记
66_采用aidl挂断电话
发布时间:2021-03-09 14:27:24编辑:雪饮阅读()
这次要实现当来电的时候通过我们的项目来把电话挂掉或者再次拨出一个电话
<androidx.constraintlayout.widget.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=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="bottom"
>
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="endcall"
android:text="挂断电话" />
<Button
android:id="@+id/button2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="startcall"
android:text="拨打电话" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
即便其中有一个权限,需要动态申请,但是据说动态申请的权限也必须要在清单文件中有所配置
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.endcall">
<uses-permission android:name="android.permission.CALL_PHONE" />
<!--
原本应该是用这个
<users-permission android:name="android.permission.MODIFY_PHONE_STATE"/>
由于这个权限是系统权限,用users前缀,在安卓6.0开始就调整了为系统权限,不是某个应用可以调用的,所以如果还以users前缀,这里会在Android studio中已经出现红色警告
这个权限据说要动态获取,在6.0开始
但是我没有动态获取成功
据说还可以做成系统应用(安装在系统目录中,而不是普通应用的安装目录)或者对应系统签名(比如对应这个权限所需要的签名)就可以
这两个的条件都比较苛刻,这里没有深究这个了,只是让项目不会因此而报错而已
有资料说要动态申请,但是我尝试了,动态申请也没有出现用户授权的弹窗(在模拟器中(api 28)测试的,不知道真机会如何),据说因为这个权限已经明确了普通应用无法获取
所以就默认拒绝了,所以也就不会有弹窗了
-->
<permission android:name="android.permission.MODIFY_PHONE_STATE"/>
<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/Theme.Endcall">
<activity android:name="com.example.endcall.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
接下来是MainActivity.java主程序:
package com.example.endcall;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
//默认的Manifest包使用时候有可能会报错“程序包Manifest不存在”,所以需要导入下面这个Manifest包
import android.Manifest;
import com.android.internal.telephony.ITelephony;
import java.lang.reflect.Method;
public class MainActivity extends AppCompatActivity {
private static final String LOG_TAG ="MainActivity" ;
private static final int PERMISSION_REQ_ID = 22;
private static final String[] REQUESTED_PERMISSIONS = {Manifest.permission.MODIFY_PHONE_STATE};
ITelephony iTelephony;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//检查权限
if (checkSelfPermission(REQUESTED_PERMISSIONS[0], PERMISSION_REQ_ID)) {
try {
// 获取系统电话管理的服务
Method method = Class.forName("android.os.ServiceManager").getMethod("getService", String.class);
IBinder binder = (IBinder)method.invoke(null, new Object[]{TELEPHONY_SERVICE});
iTelephony = ITelephony.Stub.asInterface(binder);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public boolean checkSelfPermission(String permission, int requestCode) {
Log.i(LOG_TAG, "checkSelfPermission " + permission + " " + requestCode);
if (ContextCompat.checkSelfPermission(this,permission)!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,REQUESTED_PERMISSIONS,requestCode);
return false;
}
return true;
}
@Override
public void onRequestPermissionsResult(int requestCode,@NonNull String permissions[], @NonNull int[] grantResults) {
Log.i(LOG_TAG, "onRequestPermissionsResult " + grantResults[0] + " " + requestCode);
switch (requestCode) {
case PERMISSION_REQ_ID: {
if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
showLongToast("Need permissions " + Manifest.permission.MODIFY_PHONE_STATE);
finish();
break;
}
//initAgoraEngineAndJoinChannel();//获取权限后要执行的代码
break;
}
}
}
public final void showLongToast(final String msg) {
this.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();
}
});
}
public void endcall(View view){
try {
iTelephony.endCall();
} catch (RemoteException e) {
e.printStackTrace();
}
}
public void startcall(View view){
try {
iTelephony.call("13916354914");
} catch (RemoteException e) {
e.printStackTrace();
}
}
}在“程序包Manifest不存在”这个错误出现时候会出现在控制台的builld output选项卡中,由于包含有中文,所以可能会乱码,导致你不知道具体出现了什么错误。可以按如下步骤来解决。
双击shift 弹出如下窗口 选择Actions 找到Edit Custom VM Options 打开
如果第一次编辑这个,则这个文件可能没有,则会自动弹窗问你是否要创建这个文件,那么是当然的
创建之后/打开后输入 -Dfile.encoding=UTF-8 保存后重启android studio之后就不乱码了
此外还需要依赖两个aidl
NeighboringCellInfo.aidl:
/* //device/java/android/android/content/Intent.aidl
**
** Copyright 2007, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
package android.telephony;
parcelable NeighboringCellInfo;ITelephony.aidl:
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.internal.telephony;
import android.os.Bundle;
import java.util.List;
import android.telephony.NeighboringCellInfo;
/**
* Interface used to interact with the phone. Mostly this is used by the
* TelephonyManager class. A few places are still using this directly.
* Please clean them up if possible and use TelephonyManager insteadl.
*
* {@hide}
*/
interface ITelephony {
/**
* Dial a number. This doesn't place the call. It displays
* the Dialer screen.
* @param number the number to be dialed. If null, this
* would display the Dialer screen with no number pre-filled.
*/
void dial(String number);
/**
* Place a call to the specified number.
* @param number the number to be called.
*/
void call(String number);
/**
* If there is currently a call in progress, show the call screen.
* The DTMF dialpad may or may not be visible initially, depending on
* whether it was up when the user last exited the InCallScreen.
*
* @return true if the call screen was shown.
*/
boolean showCallScreen();
/**
* Variation of showCallScreen() that also specifies whether the
* DTMF dialpad should be initially visible when the InCallScreen
* comes up.
*
* @param showDialpad if true, make the dialpad visible initially,
* otherwise hide the dialpad initially.
* @return true if the call screen was shown.
*
* @see showCallScreen
*/
boolean showCallScreenWithDialpad(boolean showDialpad);
/**
* End call or go to the Home screen
*
* @return whether it hung up
*/
boolean endCall();
/**
* Answer the currently-ringing call.
*
* If there's already a current active call, that call will be
* automatically put on hold. If both lines are currently in use, the
* current active call will be ended.
*
* TODO: provide a flag to let the caller specify what policy to use
* if both lines are in use. (The current behavior is hardwired to
* "answer incoming, end ongoing", which is how the CALL button
* is specced to behave.)
*
* TODO: this should be a oneway call (especially since it's called
* directly from the key queue thread).
*/
void answerRingingCall();
/**
* Silence the ringer if an incoming call is currently ringing.
* (If vibrating, stop the vibrator also.)
*
* It's safe to call this if the ringer has already been silenced, or
* even if there's no incoming call. (If so, this method will do nothing.)
*
* TODO: this should be a oneway call too (see above).
* (Actually *all* the methods here that return void can
* probably be oneway.)
*/
void silenceRinger();
/**
* Check if we are in either an active or holding call
* @return true if the phone state is OFFHOOK.
*/
boolean isOffhook();
/**
* Check if an incoming phone call is ringing or call waiting.
* @return true if the phone state is RINGING.
*/
boolean isRinging();
/**
* Check if the phone is idle.
* @return true if the phone state is IDLE.
*/
boolean isIdle();
/**
* Check to see if the radio is on or not.
* @return returns true if the radio is on.
*/
boolean isRadioOn();
/**
* Check if the SIM pin lock is enabled.
* @return true if the SIM pin lock is enabled.
*/
boolean isSimPinEnabled();
/**
* Cancels the missed calls notification.
*/
void cancelMissedCallsNotification();
/**
* Supply a pin to unlock the SIM. Blocks until a result is determined.
* @param pin The pin to check.
* @return whether the operation was a success.
*/
boolean supplyPin(String pin);
/**
* Handles PIN MMI commands (PIN/PIN2/PUK/PUK2), which are initiated
* without SEND (so <code>dial</code> is not appropriate).
*
* @param dialString the MMI command to be executed.
* @return true if MMI command is executed.
*/
boolean handlePinMmi(String dialString);
/**
* Toggles the radio on or off.
*/
void toggleRadioOnOff();
/**
* Set the radio to on or off
*/
boolean setRadio(boolean turnOn);
/**
* Request to update location information in service state
*/
void updateServiceLocation();
/**
* Enable location update notifications.
*/
void enableLocationUpdates();
/**
* Disable location update notifications.
*/
void disableLocationUpdates();
/**
* Enable a specific APN type.
*/
int enableApnType(String type);
/**
* Disable a specific APN type.
*/
int disableApnType(String type);
/**
* Allow mobile data connections.
*/
boolean enableDataConnectivity();
/**
* Disallow mobile data connections.
*/
boolean disableDataConnectivity();
/**
* Report whether data connectivity is possible.
*/
boolean isDataConnectivityPossible();
Bundle getCellLocation();
/**
* Returns the neighboring cell information of the device.
*/
List<NeighboringCellInfo> getNeighboringCellInfo();
int getCallState();
int getDataActivity();
int getDataState();
/**
* Returns the current active phone type as integer.
* Returns TelephonyManager.PHONE_TYPE_CDMA if RILConstants.CDMA_PHONE
* and TelephonyManager.PHONE_TYPE_GSM if RILConstants.GSM_PHONE
*/
int getActivePhoneType();
/**
* Returns the CDMA ERI icon index to display
*/
int getCdmaEriIconIndex();
/**
* Returns the CDMA ERI icon mode,
* 0 - ON
* 1 - FLASHING
*/
int getCdmaEriIconMode();
/**
* Returns the CDMA ERI text,
*/
String getCdmaEriText();
/**
* Returns true if CDMA provisioning needs to run.
*/
boolean getCdmaNeedsProvisioning();
/**
* Returns the unread count of voicemails
*/
int getVoiceMessageCount();
/**
* Returns the network type
*/
int getNetworkType();
/**
* Return true if an ICC card is present
*/
boolean hasIccCard();
}最后就可以部署到设备中进行测试了,虽然有点遗憾,安卓6之后android.permission.MODIFY_PHONE_STATE权限的获取是个大问题
关键字词:android,aidl,MODIFY_PHONE_STATE
下一篇:67_音乐播放器