android 提示音关闭连接外设提示音

【方法】android设备连接蓝牙外设导致activity重启的问题
于是将这几个configChange逐一加入进行问题排查,最终发现是navigation导致的。
回想一下,我连接的是蓝牙键盘,连接后确实导致了navigation的类型发生变化
因为连接蓝牙键盘后,我可以使用方向键来navigate了。
让人大跌眼镜啊,实践出真知,文档不可信(android的文档尤其如此)。
不过,这个问题只出现在手头的部分nexus设备上,
还是可以理解的,毕竟设备的定位摆在那里。
但鉴于nexus的设备普及率还是有一些的,仍然无法忍受这种碎片化的问题。
欢迎大家加入清源的android学习培训①群,里面有高手和干货希望你能加入进来。一起学习和交流,群号是:,加群时请验证:qy777,谢谢!&
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。Android 实现电话拦截及拦截提示音功能的开发_Android
作者:用户
本文讲的是Android 实现电话拦截及拦截提示音功能的开发_Android,
本文所讲的内容是在Android系统中如何写程序进行电话拦截,并发出拦截提示音提醒用户,可以说此功能还是比较实用的。
1、电话拦截
这个功能大家可能都知道了,就是利用反射原理调用ITelephony的隐藏方
本文所讲的内容是在Android系统中如何写程序进行电话拦截,并发出拦截提示音提醒用户,可以说此功能还是比较实用的。
1、电话拦截
这个功能大家可能都知道了,就是利用反射原理调用ITelephony的隐藏方法来实现。
2、拦截后提示忙音/空号/已关机/已停机
这个功能其实是要用到MMI指令,具体如何设置呼叫转移的指定可以参考这里 http://baike.baidu.com/view/206402.?fromTaglist。
在本文中我们会用到“遇忙转移”的功能。中国移动的设置方式是 **67#电话号码#,取消方式为 ##67#。”无条件转移“用21代替67即可。这两个指令可以直接在手机的拨号界面输入并拨号测试。ITelephony的endcall方法挂断电话后,会提示电话忙。如果事前设置好了忙时转移到一个空号/已关机/已停机的电话号码,就会提示您拨的电话号码是空号/已关机/已停机。
其实大家可以下载 xxx卫士看下,它设置来电拒接模式后,都是会启动设置MMI指令的界面。然后再去“设置-&通话设置-&来电转接”,看看 “占线时转接” 设置好的电话号码,就可以知道空号/已关机/已停机对应的电话号码是什么了。
1、修改一下BLOCKED_NUMBER这个变量值,把它设置为你要测试拦截的电话号码。
2、全部功能是在一个Activity里实现的,所以大家要先运行这个Activity,然后点击“设置呼叫转移”,设置好呼叫转移后,不要关闭这个Activity,关了就拦截不了电话了。有心的朋友可以自己去写一个Service在后台运行拦截功能。
实现方式1:
代码如下:
package net.toeach.android.
import java.lang.reflect.M
import android.app.A
import android.content.BroadcastR
import android.content.C
import android.content.I
import android.content.IntentF
import android.media.AudioM
import android.net.U
import android.os.B
import android.os.H
import android.os.M
import android.os.RemoteE
import android.telephony.TelephonyM
import android.util.L
import android.view.V
import android.view.View.OnClickL
import com.android.internal.telephony.IT
* 演示如何设置呼叫转移,拦截电话(拦截后提示为空号)的例子
* @author Tony from ToEach.
public class MainActivity extends Activity {
private static final String TAG = MainActivity.class.getSimpleName();
private final static int OP_REGISTER = 100;
private final static int OP_CANCEL = 200;
private final static String BLOCKED_NUMBER = "1892501xxxx";//要拦截的号码
//占线时转移,这里是空号,所以会提示所拨的号码为空号
private final String ENABLE_SERVICE = "tel:**67*%23";
//占线时转移
private final String DISABLE_SERVICE = "tel:%23%2367%23";
private IncomingCallReceiver mR
private ITelephony iT
private AudioManager mAudioM
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
findViewById(R.id.btnEnable).setOnClickListener(new OnClickListener(){
public void onClick(View v) {
//设置呼叫转移
Message message = mHandler.obtainMessage();
message.what = OP_REGISTER;
mHandler.dispatchMessage(message);
findViewById(R.id.btnDisable).setOnClickListener(new OnClickListener(){
public void onClick(View v) {
//取消呼叫转移
Message message = mHandler.obtainMessage();
message.what = OP_CANCEL;
mHandler.dispatchMessage(message);
mReceiver = new IncomingCallReceiver();
IntentFilter filter = new IntentFilter("android.intent.action.PHONE_STATE");
registerReceiver(mReceiver, filter);// 注册BroadcastReceiver
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
//利用反射获取隐藏的endcall方法
TelephonyManager telephonyMgr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
Method getITelephonyMethod = TelephonyManager.class.getDeclaredMethod("getITelephony", (Class[]) null);
getITelephonyMethod.setAccessible(true);
iTelephony = (ITelephony) getITelephonyMethod.invoke(telephonyMgr, (Object[]) null);
} catch (Exception e) {
e.printStackTrace();
private Handler mHandler = new Handler() {
public void handleMessage(Message response) {
int what = response.
switch(what) {
case OP_REGISTER:{
Intent i = new Intent(Intent.ACTION_CALL);
i.setData(Uri.parse(ENABLE_SERVICE));
startActivity(i);
case OP_CANCEL:{
Intent i = new Intent(Intent.ACTION_CALL);
i.setData(Uri.parse(DISABLE_SERVICE));
startActivity(i);
private class IncomingCallReceiver extends BroadcastReceiver{
public void onReceive(Context context, Intent intent) {
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
Log.i(TAG, "State: "+ state);
String number = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
Log.d(TAG, "Incomng Number: " + number);
if(state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_RINGING)){//电话正在响铃
if(number.equals(BLOCKED_NUMBER)){//拦截指定的电话号码
//先静音处理
mAudioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
Log.d(TAG, "Turn ringtone silent");
//挂断电话
iTelephony.endCall();
} catch (RemoteException e) {
e.printStackTrace();
//再恢复正常铃声
mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
AndroidManifest.xml 如下:
&?xml version="1.0" encoding="utf-8"?&
&manifest xmlns:android="http://schemas.android.com/apk/res/android "
package="net.toeach.android.callforwarding"
android:versionCode="1"
android:versionName="1.0"&
&application android:icon="@drawable/icon" android:label="@string/app_name"&
&activity android:name=".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&
&/application&
&uses-sdk android:minSdkVersion="8" /&
&uses-permission android:name="android.permission.READ_PHONE_STATE"/&
&uses-permission android:name="android.permission.CALL_PHONE"/&
&/manifest&
实现方式2:
1、建立包android.refuseCalling。
refuseCalling.java代码如下:
package android.refuseC
import android.app.A
import android.net.U
import android.os.B
import java.lang.reflect.InvocationTargetE
import java.lang.reflect.M
import android.content.C
import android.content.I
import android.os.RemoteE
import android.telephony.PhoneStateL
import android.telephony.TelephonyM
import android.util.L
import android.widget.TextV
import com.android.internal.telephony.IT
public class refuseCalling extends Activity {
private static final String TAG = "Telephony";
private TextView view =
private TelephonyManager tManager =
private ITelephony iTelephony =
//占线时转移,提示所拨的号码为空号
private final String ENABLE_SERVICE = "tel:**67*%23";
//占线时转移,提示所拨的号码为关机
private final String ENABLE_POWEROFF_SERVICE = "tel:**67*%23";
//占线时转移,提示所拨的号码为停机
private final String ENABLE_STOP_SERVICE = "tel:**21*%23";
//占线时转移
private final String DISABLE_SERVICE = "tel:%23%2321%23";
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//打开监听电话功能
TelephonyManager mTelephonyMgr = (TelephonyManager) this
.getSystemService(Context.TELEPHONY_SERVICE);
mTelephonyMgr.listen(new TeleListener(),
PhoneStateListener.LISTEN_CALL_STATE);
view = new TextView(this);
view.setText("listen the state of phone\n");
setContentView(view);
tManager = (TelephonyManager)this.getSystemService(Context.TELEPHONY_SERVICE);
//初始化iTelephony
Class &TelephonyManager& c = TelephonyManager.
Method getITelephonyMethod =
getITelephonyMethod = c.getDeclaredMethod("getITelephony", (Class[])null);
getITelephonyMethod.setAccessible(true);
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
iTelephony = (ITelephony) getITelephonyMethod.invoke(tManager, (Object[])null);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
//启用空号提示
Intent i = new Intent(Intent.ACTION_CALL);
i.setData(Uri.parse(ENABLE_STOP_SERVICE));
startActivity(i);
Log.v(TAG, "启用空号提示");
class TeleListener extends PhoneStateListener {
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
switch (state) {
case TelephonyManager.CALL_STATE_IDLE: {
Log.e(TAG, "CALL_STATE_IDLE");
view.append("CALL_STATE_IDLE " + "\n");
case TelephonyManager.CALL_STATE_OFFHOOK: {
Log.e(TAG, "CALL_STATE_OFFHOOK");
view.append("CALL_STATE_OFFHOOK" + "\n");
case TelephonyManager.CALL_STATE_RINGING: {
Log.e(TAG, "CALL_STATE_RINGING");
view.append("CALL_STATE_RINGING" + "\n");
iTelephony.endCall();
} catch (RemoteException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
protected void onStop() {
super.onStop();
protected void onDestroy() {
super.onDestroy();
Intent i = new Intent(Intent.ACTION_CALL);
i.setData(Uri.parse(DISABLE_SERVICE));
startActivity(i);
2、建立包android.telephony。
NeighboringCellInfo.aidl代码如下:
package android.
3、建立包 com.android.internal.telephony。
ITelephony.aidl代码如下:
* Licensed under the android 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.
import android.os.B
import java.util.L
import android.telephony.NeighboringCellI
//import com.FrameSpeed.NeighboringCellI
* 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.
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 if there is a call in progress, otherwise does nothing.
* @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);
* [ASD2-ES1|Connice|]
boolean supplyPuk(String puk, 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,
* 1 - FLASHING
int getCdmaEriIconMode();
* Returns the CDMA ERI text,
String getCdmaEriText();
* Returns true if OTA service provisioning needs to run.
* Only relevant on some technologies, others will always
* return false.
boolean needsOtaServiceProvisioning();
* Returns the unread count of voicemails
int getVoiceMessageCount();
* Returns the network type
int getNetworkType();
* Return true if an ICC card is present
boolean hasIccCard();
parcelable NeighboringCellI
4、AndroidManifest.xml代码如下:
&?xml version="1.0" encoding="utf-8"?&
&manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.refuseCalling"
android:versionCode="1"
android:versionName="1.0"&
&uses-permission android:name="android.permission.READ_PHONE_STATE" /&
&uses-permission android:name="android.permission.CALL_PHONE" /&
&uses-permission android:name="android.permission.MODIFY_PHONE_STATE" /&
&application android:icon="@drawable/icon" android:label="@string/app_name"&
&activity android:name=".refuseCalling"
android:label="@string/app_name"&
&intent-filter&
&action android:name="android.intent.action.MAIN" /&
&category android:name="android.intent.category.LAUNCHER" /&
&/intent-filter&
&/activity&
&/application&
&/manifest&
希望通过此文能对Android 开发电话应用的朋友提供帮助,谢谢大家对本站的支持!
以上是云栖社区小编为您精心准备的的内容,在云栖社区的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索android
实现电话拦截
电话拦截功能
android 提示音实现、android 通知拦截实现、android实现短信拦截、android搜索功能实现、android 登陆功能实现,以便于您获取更多的相关知识。
弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率
40+云计算产品,6个月免费体验
稳定可靠、可弹性伸缩的在线数据库服务,全球最受欢迎的开源数据库之一
云服务器9.9元/月,大学必备
云栖社区(yq.aliyun.com)为您免费提供相关信息,包括
,所有相关内容均不代表云栖社区的意见!&nbsp>&nbsp
&nbsp>&nbsp
&nbsp>&nbsp
快速调用Android系统提示音并播放
摘要:在开发过程中,有时候需要我们设置App推送或者消息接收时的提示音,一般为了快速快发或者设计没有给我们相应的资源时,一般都调用系统内置的提示音来完成任务.(想象一下你手机接收到短信或者推送时提示音)关键类RingtoneManager以及Ringtone两个类.RingtoneManager:系统内置提示音管理类,可以直接获取实例:newRingtoneManager(Contextcontext)该类中可以通过多种方法获取Ringtone实例。Ringtone:描述提示音的类
在开发过程中,有时候需要我们设置 App 推送或者消息接收时的提示音,一般为了快速快发或者设计没有给我们相应的资源时,一般都调用系统内置的提示音来完成任务.(想象一下你手机接收到短信或者推送时提示音)
RingtoneManager以及Ringtone两个类.
RingtoneManager:系统内置提示音管理类,可以直接获取实例:
new RingtoneManager(Context context)
该类中可以通过多种方法获取Ringtone实例。
Ringtone:描述提示音的类。 一般获取到该类的实例之后,直接调用其 play()方法,来播放音频。
简单快速获取手机当前系统提示音并播放
在清单文件中声明权限。
&uses-permission android:name=&android.permission.READ_EXTERNAL_STORAGE&/&
获取系统当前提示音打 Uri:
Uri uri = RingtoneManger.getDefaultUri(RingtoneManger.TYPE_NOTIFICATION)
通过Uri 来获取提示音的实例对象:
Ringtone mRingtone = RingtoneManager.gerRingtone(context, uri)
播放: mRingtone.play()
快速获取系统中所有的提示音
RingtoneManager manager = new RingtoneManager(context);
manager.setType(RingtoneManager.TYPE_NOTIFYICTION);
Cursor cursor = manager.getCursor();
遍历cursor,里面包含了所有系统的提示音对象。
抑或执行上面方法之后,直接通过 RingtoneManager.getRingtone(int position)来获取提示音的实例对象。
附带:快速设置震动的方法
清单文件中声明权限:VIBRATE
Vibrator vibrator = context.getSystemService(context.VIBRATOR_SERVICE);
vibrator.vibrate(500);//震动时长 ms
关于vibrator.vibrate()方法,又多个重写方法,涵盖了多种震动的方式,详情参考官方文档。
以上是的内容,更多
的内容,请您使用右上方搜索功能获取相关信息。
若你要投稿、删除文章请联系邮箱:zixun-group@service.aliyun.com,工作人员会在五个工作日内给你回复。
云服务器 ECS
可弹性伸缩、安全稳定、简单易用
&40.8元/月起
预测未发生的攻击
&24元/月起
为您提供0门槛上云实践机会
你可能还喜欢
你可能感兴趣
阿里云教程中心为您免费提供
快速调用Android系统提示音并播放相关信息,包括
的信息,所有快速调用Android系统提示音并播放相关内容均不代表阿里云的意见!投稿删除文章请联系邮箱:zixun-group@service.aliyun.com,工作人员会在五个工作日内答复
售前咨询热线
支持与服务
资源和社区
关注阿里云
Internationalandroid 如何关闭邮件讯息提示音_百度知道
android 如何关闭邮件讯息提示音
我有更好的答案
1.找到“系统设置”或“设置”,不同的手机可能会不一样。2.找到“情景模式“,选择对应的模式修改选项就可以了。
采纳率:93%
来自团队:
工具-选项-常规
为您推荐:
其他类似问题
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。在 SegmentFault,学习技能、解决问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。
标签:至少1个,最多5个
本文转自我的博客
选中拍摄时关闭声音,摄像时会有声音,设备:小米note,红米note,oppo
据查该问题属于一种防偷拍的潜规则类型设置,与android系统提供商相关,拍照/摄像的提示音所有实现都在底层实现,上层能够控制的有限。
为什么拍照可以实现静默?
静默拍照目前可以通过两种方式设置:
android4.2以上的版本可以通过Camera提供的enableShutterSound(boolean enabled)方法禁止拍照提示音;
通过调整接口使用来规避提示音,设置shutter callback为null来实现,该方法在中有提及;
这两种方法在底层的实现原理如下:
以android4.2的源码 为例,最终的提示音调用代码目录在:
// snapshot taken callback
void CameraClient::handleShutter(void) {
//mPlayShutterSound 该值从上层设置 即第一种方法提供的接口实现,4.2以上版本有效
if (mPlayShutterSound) {
//声音调用
mCameraService- &playSound(CameraService::SOUND_SHUTTER);
sp&ICameraClient& c = mCameraC
if (c != 0) {
mLock.unlock();
c-&notifyCallback(CAMERA_MSG_SHUTTER, 0, 0);
if (!lockIfMessageWanted(CAMERA_MSG_SHUTTER))
disableMsgType(CAMERA_MSG_SHUTTER);
mLock.unlock();
留意一下handleShutter的调用情况,可以发现在CameraClient中仅有一处调用了该函数:
void CameraClient::notifyCallback(int32_t msgType, int32_t ext1,
int32_t ext2, void* user) {
LOG2("notifyCallback(%d)", msgType);
Mutex* lock = getClientLockFromCookie(user);
if (lock == NULL)
Mutex::Autolock alock(*lock);
CameraClient* client =
static_cast&CameraClient*&(getClientFromCookie(user));
if (client == NULL)
if (!client-&lockIfMessageWanted(msgType))
switch (msgType) {
case CAMERA_MSG_SHUTTER:
// 控制发声
// ext1 is the dimension of the yuv picture.
client-&handleShutter();
client-&handleGenericNotify(msgType, ext1, ext2);
那么第二种规避发声的方法也有了合理的解释,底层的快门声调用放在了notifyCallback中,那么躲开了该回调的使用也就避开了快门的声音。
那么摄像的提示音呢?
摄像功能在java层是通过 MediaRecorder 类实现的,但是在java层包括它对应的jni层大多也只是包裹一个接口、注册等作用,到底层最后的实现还是在CameraClient类中,与提示音有关的代码如下:
status_t CameraClient::startRecordingMode() {
LOG1("startRecordingMode");
status_t result = NO_ERROR;
// if recording has been enabled, nothing needs to be done
if (mHardware-&recordingEnabled()) {
return NO_ERROR;
// if preview has not been started, start preview first
if (!mHardware-&previewEnabled()) {
result = startPreviewMode();
if (result != NO_ERROR) {
// start recording mode
enableMsgType(CAMERA_MSG_VIDEO_FRAME);
//提示音代码
mCameraService-&playSound(CameraService::SOUND_RECORDING);
result = mHardware-&startRecording();
if (result != NO_ERROR) {
ALOGE("mHardware-&startRecording() failed with status %d", result);
关联代码上下文可以发现startRecordingMode本函数无法规避,想要通过该类实现录像功能这是必走的流程,所以相对而言正规取巧的方法在上层理论上无法操控。能够看出的是4.2中也没有预留标志位给上层去控制。
一些野路子方法如下:
方案一:拍摄开始时设置系统音频流静默并调整音量为0,结束时恢复;
方案二:找到提示音文件,通过改名/移动等方法让发音失灵,由于音频文件在系统中,所以需要root权限,该方案对用户要求比较高,不考虑;
经过测试,方案一能够搞定一部分机型的情况,但不是所有的,如中兴、小米的机器都是无效的,在一篇博客中找到了一种解释:
但是需要注意的是:很多机器是强制快门音的,也就是说你在app里调用上述接口也许根本不起作用,你明明enableShutterSound(false)了,但是拍照的时候快门音照样响起,原因在于烧制的系统版本里面有一个值被写死了:ro.camera.sound.forced = 1
在CameraClient代码中找一下这个系统属性值可以找到:
// enable shutter sound
status_t CameraClient::enableShutterSound(bool enable) {
LOG1("enableShutterSound (pid %d)", getCallingPid());
status_t result = checkPidAndHardware();
if (result != NO_ERROR)
if (enable) {
mPlayShutterSound =
return OK;
// Disabling shutter sound may not be allowed. In that case only
// allow the mediaserver process to disable the sound.
char value[PROPERTY_VALUE_MAX];
//取到系统值来控制 mPlayShutterSound 设置权限
property_get("ro.camera.sound.forced", value, "0");
if (strcmp(value, "0") != 0) {
// Disabling shutter sound is not allowed. Deny if the current
// process is not mediaserver.
if (getCallingPid() != getpid()) {
ALOGE("Failed to disable shutter sound. Permission denied (pid %d)", getCallingPid());
return PERMISSION_DENIED;
mPlayShutterSound =
return OK;
那么很明显,在CameraClient中这个系统值的作用就是限制 mPlayShutterSound 的设置了,也是对引文那一段的解释。我们在源码的全局范围内,可以发现除了 mPlayShutterSound 该值相关的几个cpp类中有相关的使用以外,audio_policy_hal.cpp 在该类中也可以找到对forced值的使用,经过查询可以了解到这部分是实现了提示音无视静音的功能,原理大概是在播放提示音的时候会将音量调到最大,详细的过程讲解博客见。也就是说部分设置了ro.camera.sound.forced 的系统,采用强制静音或者调音量的方法行不通,该问题基本无解。
从测试的情况看,ZTE Q801L是可以通过命令获取到ro.camera.sound.forced为1的,实现上确实无法静默拍摄;而小米则比较有意思,首先它无法获取到forced值,但是从表现上看小米原生的相机是静默的、第三方的相机则静默不了,可以推测是MiUI内部有相关的内部接口或者公用属性去设置来控制。
对于无root的应用层而言,使用系统提供的MediaRecorder实现的,针对系统的不同有以下几种情况:
系统强制发音,设置了ro.camera.sound.forced的,无解;-- 如中兴ZTE Q801L
定制化系统提供了内部接口的并且外在表现为强制发音的,暂时无解。或许可以有针对性的的对相关的定制系统查找相关的方法;--如小米note、红米note
系统未强制设定的,一部分无需设置(如htc、三星);一部分可以通过提供静音策略来限制,这部分要保证不引发其他的音频类型问题;(魅族?)
除此之外,自定义编写视频录制实现也是个方案,不过工作量需要评估。
1 收藏&&|&&1
你可能感兴趣的文章
4 收藏,2.6k
2 收藏,1.7k
分享到微博?
我要该,理由是:
在 SegmentFault,学习技能、解决问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。

我要回帖

更多关于 android 通知提示音 的文章

 

随机推荐