精华内容
下载资源
问答
  • 1. 如何判断手机是否处于正在通话中?(任何时候都可以判断手机是否处于通过中) private boolean phoneIsInUse() { boolean phoneInUse = false; try { ITelephony phone = ITelephony.Stub.asInterface...
    1. 如何判断手机是否处于正在通话中?(任何时候都可以判断手机是否处于通过中)
    private boolean phoneIsInUse() {
    boolean phoneInUse = false;
    try {
    ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
    if (phone != null) phoneInUse = !phone.isIdle();
    } catch (RemoteException e) {
    Log.w(TAG, "phone.isIdle() failed", e);
    }
    return phoneInUse;
    }

    2.通话状态的判断(需要注册监听以后,才可以判断手机通话状态的改变,可能连续接收到同一个状态的改变)

    package cn.com.chenzheng_java;

    import android.app.Activity;
    import android.os.Bundle;
    import android.telephony.PhoneStateListener;
    import android.telephony.TelephonyManager;
    import android.widget.TextView;
    /**
    *
    * @author
    * @description 通过该实例,我们可以看到,如果我们想要监听电话的拨打状况,需要这么几步
    * 第一:获取电话服务管理器TelephonyManager manager = this.getSystemService(TELEPHONY_SERVICE);
    * 第二:通过TelephonyManager注册我们要监听的电话状态改变事件。manager.listen(new MyPhoneStateListener(),
    * PhoneStateListener.LISTEN_CALL_STATE);这里的PhoneStateListener.LISTEN_CALL_STATE就是我们想要
    * 监听的状态改变事件,初次之外,还有很多其他事件哦。
    * 第三步:通过extends PhoneStateListener来定制自己的规则。将其对象传递给第二步作为参数
    * 第四步:这一步很重要,那就是给应用添加权限。android.permission.READ_PHONE_STATE
    *
    *
    */
    public class PhoneCallStateActivity extends Activity {
    TelephonyManager manager ;
    String result = "监听电话状态:/n";
    TextView textView ;
    @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    //获取电话服务
    manager = (TelephonyManager) this.getSystemService(TELEPHONY_SERVICE);
    // 手动注册对PhoneStateListener中的listen_call_state状态进行监听
    manager.listen(new MyPhoneStateListener(), PhoneStateListener.LISTEN_CALL_STATE);

    textView = (TextView) findViewById(R.id.textView1);
    textView.setText(result);
    }
    /***
    * 继承PhoneStateListener类,我们可以重新其内部的各种监听方法
    *然后通过手机状态改变时,系统自动触发这些方法来实现我们想要的功能
    */
    class MyPhoneStateListener extends PhoneStateListener{

    @Override
    public void onCallStateChanged(int state, String incomingNumber) {
    switch (state) {
    case TelephonyManager.CALL_STATE_IDLE:
    result+=" 手机空闲起来了 ";
    break;
    case TelephonyManager.CALL_STATE_RINGING:
    result+=" 手机铃声响了,来电号码:"+incomingNumber;
    break;
    case TelephonyManager.CALL_STATE_OFFHOOK:
    result+=" 电话被挂起了 ";
    default:
    break;
    }
    textView.setText(result);
    super.onCallStateChanged(state, incomingNumber);
    }

    }


    }
    这里一定要注意,别忘记给应用注册权限:
    <uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
    展开全文
  • Android 判断手机通话的几种状态,比如正在通话状态、等待用户接听状态、手机处于待机状态、电话已接通、有来电并显示电话号码。程序还支持未接电话自动发短信功能,当判断出“我现在不方便接电话,稍后打给你”时,...
  • Android手机的休眠状态

    万次阅读 2015-06-30 15:46:18
    通话时间,BP的能耗基本上在5mA左右,而AP只要处于非休眠状态,能耗至少在50mA以上,执行图形运算时会更高。一般手机待机时,AP、LCD、WIFI均进入休眠状态,这时Android中应用程序的代码也会停止执行。Android为了...
    • 任何一个应用申请了 wakelock 锁,待机(按:什么是待机?待机与屏幕黑、锁屏、休眠的关系是什么?)时没有释放掉,系统是不会进入待机的,直到所有应用的 wakelock 锁都释放掉了,才会进入待机。

    • 如果不进行特别的设置,Android会在一定时间后屏幕变暗,在屏幕变暗后一定时间内,CPU也会休眠,大多数的程序都会停止运行,从而节省电量。

    • Android手机有两个处理器,一个叫Application Processor(AP),一个叫Baseband Processor(BP)。非通话时间,BP的能耗基本上在5mA左右,而AP只要处于非休眠状态,能耗至少在50mA以上,执行图形运算时会更高。一般手机待机时,AP、LCD、WIFI均进入休眠状态,这时Android中应用程序的代码也会停止执行。Android为了确保应用程序中关键代码的正确执行,提供了Wake Lock的API,使得APP可以通过之阻止AP进入休眠。但不一定必要,首先,完全没必要担心AP休眠会导致收不到消息推送。通讯协议栈运行于BP,一旦收到数据包(按:收到 TCP 数据包才会唤醒 AP,UDP 包不会唤醒),BP会将AP唤醒,唤醒的时间足够AP执行代码完成对收到的数据包的处理过程。其它的如Connectivity事件触发时AP同样会被唤醒。那么唯一的问题就是程序如何执行向服务器发送心跳包的逻辑。你显然不能靠AP来做心跳计时。Android提供的Alarm Manager就是来解决这个问题的。Alarm应该是BP计时(或其它某个带石英钟的芯片,不太确定,但绝对不是AP),触发时唤醒AP执行程序代码。那么Wake Lock API有啥用呢?比如心跳包从请求到应答,比如断线重连重新登陆这些关键逻辑的执行过程,就需要Wake Lock来保护(按:只在这些关键逻辑时,需要Wake Lock API确保不休眠)。而一旦一个关键逻辑执行成功,就应该立即释放掉Wake Lock了。两次心跳请求间隔5到10分钟,基本不会怎么耗电。除非网络不稳定,频繁断线重连,那种情况办法不多。

    • 网上有说使用AlarmManager,因为AlarmManager 是Android 系统封装的用于管理 RTC 的模块,RTC (Real Time Clock) 是一个独立的硬件时钟,可以在 CPU 休眠时正常运行,在预设的时间到达时,通过中断唤醒 CPU。

    • 休眠有early suspend和suspend,early suspend是可以通过alarm来唤醒的,但是suspend没法通过alarm来唤醒,进入suspend之后系统自带的闹钟程序都不会起作用了(按:待求证)。

    • Android 设置–> WLAN –>点击菜单键 选择 高级 –>休眠状态下保持WLAN连接的下拉列表{始终、仅限充电时、从不(会增加数据流量)},如果设置不为始终,那么我们锁屏休眠后,程序将会处于无网络状态,相应的app用户会一直处于离线模式。

    • 开发中,可以在程序开启时,读取Settings.System.WIFI_SLEEP_POLICY值,保存起来,再将其值改为WIFI_SLEEP_POLICY_NEVER使本程序运行期间保持wifi连接,待程序退出时,将原先保存的值还原。

    • 如下表,休眠有多种等级,最高等级的休眠是屏幕、键盘、cpu全部休眠:

    Flag Value CPU Screen Keyboard
    PARTIAL_WAKE_LOCK On Off Off
    SCREEN_DIM_WAKE_LOCK On Dim Off
    SCREEN_BRIGHT_WAKE_LOCK On Bright Off
    FULL_WAKE_LOCK On Bright Bright

    可以设置不同的模式,让其产生不同的休眠,比如让cpu保持运行。
    设置代码如下:

    PowerManagerpm =(PowerManager)getSystemService(Context.POWER_SERVICE);
    PowerManager.WakeLockwl =pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK,"My Tag");
    wl.acquire();
    wl.release();
    • 休眠几个坑点及解决:
      1.向服务器轮询的代码不执行:曾经做一个应用,利用Timer和TimerTask,来设置对服务器进行定时的轮询,但是发现机器在某段时间后,轮询就不再进行了。查了很久才发现是休眠造成的。后来解决的办法是,利用系统的AlarmManager来执行轮询。因为虽然系统让机器休眠,节省电量,但并不是完全的关机,系统有一部分优先级很高的程序还是在执行的,比如闹钟,利用AlarmManager可以定时启动自己的程序,让cpu启动,执行完毕再休眠(按:如上述,就是通过 BP 唤醒 AP)。
      2.后台长连接断开:最近遇到的问题。利用Socket长连接实现QQ类似的聊天功能,发现在屏幕熄灭一段时间后,Socket就被断开。屏幕开启的时候需进行重连,但每次看Log的时候又发现网络是链接的,后来才发现是cpu休眠导致链接被断开,当你插上数据线看log的时候,网络cpu恢复,一看网络确实是链接的, 坑。最后使用了PARTIAL_WAKE_LOCK,保持CPU不休眠。
      3.调试时是不会休眠的:在调试2的时候,就发现,有时Socket会断开,有时不会断开,后来才搞明白,因为我有时是插着数据线进行调试,有时拔掉数据线,这时Android的休眠状态是不一样的。而且不同的机器也有不同的表现,比如有的机器,插着数据线就会充电,有的不会,有的机器的设置的充电时屏幕不变暗等等。
    展开全文
  • 有电话拨入,处于响铃状态,响铃状态通过代码去挂断电话(aidl,反射),拦截电话 挂断电话号码的方法,放置在了aidl文件中名称为endCall在此处去查看TelePhoneManager源码,去查找获取ITelephony对象的方法ServiceManager...

    首先对功能简单分析一下,既然是黑名单功能,那么肯定是写在服务里面,需要一直在后台运行着。
    一、拦截短信
    短信在接收的时候,广播发送,监听广播接受者,拦截短信(有序广播)
    将广播的优先级级别提高到最高 (1000)
    二、 拦截电话
    有电话拨入,处于响铃状态,响铃状态通过代码去挂断电话(aidl,反射),拦截电话
    挂断电话号码的方法,放置在了aidl文件中,方法名为endCall
    在此处去查看TelePhoneManager源码,去查找获取ITelephony对象的方法
    ServiceManager此类android对开发者隐藏,所以不能去直接调用其方法,所以需要反射调用
    ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));

    1,获取ServiceManager字节码文件
    Class

    代码:

    package com.wutao.mobilesafe.service;
    
    import android.app.Service;
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.content.IntentFilter;
    import android.database.ContentObserver;
    import android.net.Uri;
    import android.os.Handler;
    import android.os.IBinder;
    import android.support.annotation.Nullable;
    import android.telephony.PhoneStateListener;
    import android.telephony.SmsMessage;
    import android.telephony.TelephonyManager;
    
    import com.android.internal.telephony.ITelephony;
    import com.wutao.mobilesafe.db.dao.BlackNumberDao;
    
    import java.lang.reflect.Method;
    
    /**
     * Created by 凸显 on 2016/8/14.
     */
    public class BlackNumberService extends Service {
        private InnerSmsReceiver mInnerSmsReceiver;
        private BlackNumberDao mDB;
        private TelephonyManager mTM;
        private MyPhoneStateListener mPhoneStateListener;
        private MyContentObserver mContentObserver;
    
        @Override
        public void onCreate() {
            mDB = BlackNumberDao.getInstance(getApplicationContext());
            //拦截短信,注册短信监听的广播
            IntentFilter intentFilter = new IntentFilter();
            intentFilter.addAction("android.provider.Telephony.SMS_RECEIVED");
            intentFilter.setPriority(1000);
            mInnerSmsReceiver = new InnerSmsReceiver();
            registerReceiver(mInnerSmsReceiver, intentFilter);
    
            //电话状态的监听(服务开启的时候,需要去做监听,关闭的时候电话状态就不需要监听)
            //1,电话管理者对象
            mTM = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
            //监听电话状态
            mPhoneStateListener = new MyPhoneStateListener();
            mTM.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
            super.onCreate();
        }
    
        class MyPhoneStateListener extends PhoneStateListener {
            @Override
            public void onCallStateChanged(int state, String incomingNumber) {
                switch (state) {
                    //空闲状态,没有任何活动(移除吐司)
                    case TelephonyManager.CALL_STATE_IDLE:
                        break;
                    //摘机状态,至少有个电话活动。该活动或是拨打(dialing)或是通话
                    case TelephonyManager.CALL_STATE_OFFHOOK:
                        break;
                    //响铃
                    case TelephonyManager.CALL_STATE_RINGING:
                        //挂断电话
                        endCall(incomingNumber);
                        break;
                }
                super.onCallStateChanged(state, incomingNumber);
            }
        }
    
        private void endCall(String number) {
            int mode = mDB.getMode(number);
            if (mode == 2 || mode == 3) {
    //      ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE))
    //      ServiceManager此类android对开发者隐藏,所以不能去直接调用其方法,需要反射调用
    //      首先需要导入aidl文件
                try {
                    //获取ServiceManager字节码文件
                    Class<?> clazz = Class.forName("android.os.ServiceManager");
                    //获取方法
                    Method method = clazz.getMethod("getService", String.class);
                    //静态方法直接调用
                    IBinder iBinder = (IBinder) method.invoke(null, Context.TELEPHONY_SERVICE);
                    //调用获取aidl文件对象方法
                    ITelephony iTelephony = ITelephony.Stub.asInterface(iBinder);
                    //调用在aidl中隐藏的endCall方法挂断电话
                    iTelephony.endCall();
    
                    //在内容解析器上,去注册内容观察者,通过内容观察者,观察数据库(Uri决定那张表那个库)的变化
                    mContentObserver = new MyContentObserver(new Handler(), number);
                    getContentResolver().registerContentObserver(
                            Uri.parse("content://call_log/calls"), true, mContentObserver);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    
        class MyContentObserver extends ContentObserver {
            private String phone;
    
            public MyContentObserver(Handler handler, String phone) {
                super(handler);
                this.phone = phone;
            }
    
            //数据库中指定calls表发生改变的时候会去调用方法
            @Override
            public void onChange(boolean selfChange) {
                //当插入一条数据后,再进行删除
                getContentResolver().delete(
                        Uri.parse("content://call_log/calls"), "number = ?", new String[]{phone});
                super.onChange(selfChange);
            }
        }
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    
        private class InnerSmsReceiver extends BroadcastReceiver {
            @Override
            public void onReceive(Context context, Intent intent) {
                //获取短信内容
                Object[] objects = (Object[]) intent.getExtras().get("pdus");
                for (Object object : objects) {
                    //获取短信对象
                    SmsMessage sms = SmsMessage.createFromPdu((byte[]) object);
                    //获取短信对象的基本信息
                    String address = sms.getOriginatingAddress();//拨入的电话号码
                    String messageBody = sms.getMessageBody();
                    int mode = mDB.getMode(address);
                    if (mode == 1 || mode == 3) {
                        //拦截短信(android 4.4版本失效  短信数据库,删除)
                        abortBroadcast();
                    }
                }
            }
        }
    
        @Override
        public void onDestroy() {
            //当服务销毁时,广播也销毁
            if (mInnerSmsReceiver != null) {
                unregisterReceiver(mInnerSmsReceiver);
            }
            //注销内容观察者
            if (mContentObserver != null) {
                getContentResolver().unregisterContentObserver(mContentObserver);
            }
            //取消电话状态的监听
            if (mPhoneStateListener != null) {
                mTM.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
            }
            super.onDestroy();
        }
    }
    
    展开全文
  • android 通话自动录音服务

    千次阅读 2017-02-25 14:48:43
    需求: ①:通话自动录音; ②:无界面,只是一个service;...启动一个service,监听用户手机通话状态,当检测到用户处于通话状态下,立即开始录音,通话结束后,停止录音,并保存文件。 此功能的前提条件:

    需求:
    ①:通话自动录音;
    ②:无界面,只是一个service;
    ③:录音自动压缩上传;
    ④:当用户清理后台的时候,要求service不可以被杀死;
    ⑤:稳定性:1、无网络的情况下;2、上传失败;3、服务报错。
    解决方案:
    ①:通话自动录音
    启动一个service,监听用户手机通话状态,当检测到用户处于通话状态下,立即开始录音,通话结束后,停止录音,并保存文件。
    此功能的前提条件:
    1、录音权限、读写存储空间的权限、读取通话状态的权限;
    2、Service不可以被停止,否则无法录音。
    3、开机启动(不可以让用户每次开机都主动去打开服务)
    ②:无界面,只是一个service
    方案①
    普通的service,监听开机广播,当用户开机的时候,启动service。但是,发现service并没有启动。想要启动一个service,必须要有一个activity,即使你不打开这个activity。
    在真正做项目的时候,PM会提出各种你不能理解的需求,比如说本系统,PM要求本应用只是一个录音服务,不可以有任何界面,也不可以在手机桌面上出现应用图标。因此,方案①不可行。
    方案②
    Android手机在设置里面都一个辅助功能(个别手机也叫:无障碍),利用这个我们可以实现一些强大的功能,前提是用户开启我们的辅助功能,抢红包软件就是利用辅助功能实现的。
    这里写图片描述这里写图片描述
    ③:录音自动压缩上传
    我们只需要在上传之前对文件进行压缩处理,然后再上传即可。
    ④:当用户清理后台的时候,要求service不可以被杀死
    不会被杀死的服务,或许只有系统服务吧。当然类似于QQ、微信他们做的这种全家桶也可以做到。大公司是可以和厂商合作的,他们的应用可以不那么容易被杀死。当然也不提倡这样做,这样就是垃圾软件,破坏了Android开发的美好环境。
    其实,如果可以把服务设置成系统服务,那么只要用户不主动在辅助功能页面关掉服务,后台是清理不掉改服务的。本人在小米手机上测试过,设置成系统级别的服务后,当清理后台的时候,即使服务被杀死,也会非常快的重新启动。(感兴趣的同学可以试一下)
    ⑤:稳定性:1、无网络的情况下;2、上传失败;3、服务报错
    思路:
    当无网络的情况下,把录音文件的地址保存下来(保存的方式有很多:Sqlite、Sharedpreferences等等),上传失败也一样,失败的原因可能有很多种:网络断开、接口报错等,当网络恢复的时候,可以重新上传,这样就不会丢失录音文件。
    代码很简单,注释很详细:
    项目的结构:这里写图片描述

    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <!-- 要存储文件或者创建文件夹的话还需要以下两个权限 -->
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.INTERNET"/>
    <!--允许读取网络状态-->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <!--允许读取wifi网络状态-->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    <service
        android:name=".service.RecorderService"
        android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
        <intent-filter>
            <action android:name="android.accessibilityservice.AccessibilityService" />
        </intent-filter>
        <meta-data
            android:name="android.accessibilityservice"
            android:resource="@xml/accessible_service_config" />
    </service>
    /**
     * 电话自动录音辅助服务(去电、来电自动录音并上传)。
     * Created by wang.ao in 2017/2/24.
     */
    
    public class RecorderService extends AccessibilityService {
        private static final String TAG = "RecorderService";
        private static final String TAG1 = "手机通话状态";
        /**
         * 音频录制
         */
        private MediaRecorder recorder;
        private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        /**
         * 监听拨号广播,以便获取用户拨出的电话号码
         */
        private OutCallReceiver outCallReceiver;
        private IntentFilter intentFilter;
        /**
         * 网络状态改变广播,当网络畅通的状态下,把用户未上传的录音文件都上传掉
         */
        private NetworkConnectChangedReceiver networkConnectChangedReceiver;
        private IntentFilter intentFilter2;
        /**
         * 当前通话对象的电话号码
         */
        private String currentCallNum = "";
        /**
         * 区分来电和去电
         */
        private int previousStats = 0;
        /**
         * 当前正在录制的文件
         */
        private String currentFile = "";
        /**
         * 保存未上传的录音文件
         */
        private SharedPreferences unUploadFile;
        private String dirPath = "";
        private boolean isRecording = false;
    
        @Override
        protected void onServiceConnected() {
            Log.i(TAG, "onServiceConnected");
            Toast.makeText(getApplicationContext(), "自动录音服务已启动", Toast.LENGTH_LONG).show();
        }
    
        @Override
        public void onAccessibilityEvent(AccessibilityEvent event) {
            // TODO Auto-generated method stub
            Log.i(TAG, "eventType " + event.getEventType());
        }
    
        @Override
        public void onInterrupt() {
            // TODO Auto-generated method stub
            Log.i(TAG, "onServiceConnected");
        }
    
        @Override
        public boolean onUnbind(Intent intent) {
            return super.onUnbind(intent);
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
            // 监听电话状态
            tm.listen(new MyListener(), PhoneStateListener.LISTEN_CALL_STATE);
            outCallReceiver = new OutCallReceiver();
            intentFilter = new IntentFilter();
            //设置拨号广播过滤
            intentFilter.addAction("android.intent.action.NEW_OUTGOING_CALL");
            registerReceiver(outCallReceiver, intentFilter);
            //注册拨号广播接收器
            networkConnectChangedReceiver = new NetworkConnectChangedReceiver();
            intentFilter2 = new IntentFilter();
            //设置网络状态改变广播过滤
            intentFilter2.addAction("android.net.conn.CONNECTIVITY_CHANGE");
            intentFilter2.addAction("android.net.wifi.WIFI_STATE_CHANGED");
            intentFilter2.addAction("android.net.wifi.STATE_CHANGE");
            //注册网络状态改变广播接收器
            registerReceiver(networkConnectChangedReceiver, intentFilter2);
            unUploadFile = getSharedPreferences("un_upload_file", 0);
            unUploadFile.edit().putString("description", "未上传的录音文件存放路径").commit();
            dirPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/com.ct.phonerecorder/";
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            Toast.makeText(getApplicationContext(), "进程被关闭,无法继续录音,请打开录音服务", Toast.LENGTH_LONG).show();
            if (outCallReceiver != null) {
                unregisterReceiver(outCallReceiver);
            }
            if (networkConnectChangedReceiver != null) {
                unregisterReceiver(networkConnectChangedReceiver);
            }
        }
    
        class MyListener extends PhoneStateListener {
            @Override
            public void onCallStateChanged(int state, String incomingNumber) {
                // TODO Auto-generated method stub
                Log.d(TAG1, "空闲状态" + incomingNumber);
                switch (state) {
                    case TelephonyManager.CALL_STATE_IDLE:
                        Log.d(TAG1, "空闲");
                        if (recorder != null && isRecording) {
                            recorder.stop();// 停止录音
                            recorder.release();
                            recorder = null;
                            Log.d("电话", "通话结束,停止录音");
                            uploadFile(currentFile);
                        }
                        isRecording = false;
                        break;
                    case TelephonyManager.CALL_STATE_RINGING:
                        Log.d(TAG1, "来电响铃" + incomingNumber);
                        // 进行初始化
    
                        break;
                    case TelephonyManager.CALL_STATE_OFFHOOK:
                        Log.d(TAG1, "摘机" + (!incomingNumber.equals("") ? incomingNumber : currentCallNum));
                        initRecord(!incomingNumber.equals("") ? incomingNumber : currentCallNum);
                        // 开始录音
                        if (recorder != null) {
                            recorder.start();
                            isRecording = true;
                        }
                    default:
                        break;
                }
                super.onCallStateChanged(state, incomingNumber);
            }
    
        }
    
        /**
         * 当录音结束后,自动上传录音文件。
         * ①网络可用:直接上传;
         * ②网络不可用:保存文件路径,待网络可用的时候再进行上传;
         * ③上传失败的文件,也保存文件路径,或者重新上传。
         */
        public void uploadFile(String file) {
            ZipUtils.zipFile(dirPath + file, dirPath + file + ".zip");
            if (NetWorkUtils.isNetworkConnected(getApplicationContext())) {
                //上传文件
    //            OkHttpUtils.postFile()
            } else {
                saveUnUploadFIles(dirPath + file + ".zip");
            }
        }
    
        /**
         * 保存未上传的录音文件
         *
         * @param file 未上传的录音文件路径
         */
        private void saveUnUploadFIles(String file) {
            String files = unUploadFile.getString("unUploadFile", "");
            if (files.equals("")) {
                files = file;
            } else {
                StringBuilder sb = new StringBuilder(files);
                files = sb.append(";").append(file).toString();
            }
            unUploadFile.edit().putString("unUploadFile", files).commit();
        }
    
        /**
         * 上传因为网络或者其他原因,暂未上传或者上传失败的文件,重新上传
         */
        public void uploadUnUploadedFiles() {
            //获取当前还未上传的文件,并把这些文件上传
            String files = unUploadFile.getString("unUploadFile", "");
            unUploadFile.edit().putString("unUploadFile", "").commit();
            if (files.equals("")) {
                return;
            }
            String[] fileArry = files.split(";");
            int len = fileArry.length;
            for (String file : fileArry) {
                upload(file);
            }
        }
    
        /**
         * 文件上传
         *
         * @param file 要上传的文件
         */
        public void upload(final String file) {
            File file1 = new File(file);
            if (file1 == null || !file1.exists()) {
                //文件不存在
                return;
            }
            if (!NetWorkUtils.isNetworkConnected(getApplicationContext())) {
                saveUnUploadFIles(file);
                return;
            }
            Map<String, String> map = new HashMap<String, String>();
            map.put("type", "1");
            final String url = "http://192.168.1.158:8082/uploader";
            OkHttpUtils.post()//
                    .addFile("mFile", file1.getName(), file1)//
                    .url(url)//
                    .params(map).build()//
                    .execute(new StringCallback() {
    
                        @Override
                        public void onResponse(String response, int id) {
                            Log.e(TAG, "成功 response=" + response);
                        }
    
                        @Override
                        public void onError(Call call, Exception e, int id) {
                            Log.e(TAG, "失败 response=" + e.toString());
                            saveUnUploadFIles(file);
                        }
                    });
        }
    
        /**
         * 初始化录音机,并给录音文件重命名
         *
         * @param incomingNumber 通话号码
         */
        private void initRecord(String incomingNumber) {
            previousStats = TelephonyManager.CALL_STATE_RINGING;
            recorder = new MediaRecorder();
            recorder.setAudioSource(MediaRecorder.AudioSource.MIC);// Microphone
            recorder.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);// 设置输出3gp格式
            File out = new File(dirPath);
            if (!out.exists()) {
                out.mkdirs();
            }
            recorder.setOutputFile(dirPath
                    + getFileName((previousStats == TelephonyManager.CALL_STATE_RINGING ? incomingNumber : currentCallNum))
            );
            recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);// 设置音频编码格式
            try {
                recorder.prepare();// 做好准备
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    
        /**
         * 获取录音文件的名称
         *
         * @param incomingNumber 通话号码
         * @return 获取录音文件的名称
         */
        private String getFileName(String incomingNumber) {
            Date date = new Date(System.currentTimeMillis());
            currentFile = incomingNumber + " " + dateFormat.format(date) + ".mp3";
            return currentFile;
        }
    
        /**
         * 拨号广播接收器,并获取拨号号码
         */
        public class OutCallReceiver extends BroadcastReceiver {
            @Override
            public void onReceive(Context context, Intent intent) {
                Log.d(TAG1, "当前手机拨打了电话:" + currentCallNum);
                if (intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)) {
                    currentCallNum = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
                    Log.d(TAG1, "当前手机拨打了电话:" + currentCallNum);
                } else {
                    Log.d(TAG1, "有电话,快接听电话");
                }
            }
        }
    
        /**
         * 网络状态change广播接收器
         */
        public class NetworkConnectChangedReceiver extends BroadcastReceiver {
            private static final String TAG = "network status";
    
            @Override
            public void onReceive(Context context, Intent intent) {
                /**
                 * 这个监听网络连接的设置,包括wifi和移动数据的打开和关闭。.
                 * 最好用的还是这个监听。wifi如果打开,关闭,以及连接上可用的连接都会接到监听。见log
                 * 这个广播的最大弊端是比上边两个广播的反应要慢,如果只是要监听wifi,我觉得还是用上边两个配合比较合适
                 */
                if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
                    ConnectivityManager manager = (ConnectivityManager) context
                            .getSystemService(Context.CONNECTIVITY_SERVICE);
                    Log.i(TAG, "CONNECTIVITY_ACTION");
    
                    NetworkInfo activeNetwork = manager.getActiveNetworkInfo();
                    if (activeNetwork != null) { // connected to the internet
                        if (activeNetwork.isConnected()) {
                            //当前网络可用
                            if (activeNetwork.getType() == ConnectivityManager.TYPE_WIFI) {
                                // connected to wifi
                                Log.e(TAG, "当前WiFi连接可用 ");
                            } else if (activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE) {
                                // connected to the mobile provider's data plan
                                Log.e(TAG, "当前移动网络连接可用 ");
                            }
                            uploadUnUploadedFiles();
                        } else {
                            Log.e(TAG, "当前没有网络连接,请确保你已经打开网络 ");
                        }
    
                    } else {   // not connected to the internet
                        Log.e(TAG, "当前没有网络连接,请确保你已经打开网络 ");
                    }
    
    
                }
            }
        }
    
    }
    /**
     * 获取网络连接状态工具类
     * Created by wang.ao in 2017/2/24.
     */
    
    public class NetWorkUtils {
        /**
         * 判断是否有网络连接
         * @param context
         * @return
         */
        public static boolean isNetworkConnected(Context context) {
            if (context != null) {
                ConnectivityManager mConnectivityManager = (ConnectivityManager) context
                        .getSystemService(Context.CONNECTIVITY_SERVICE);
                NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
                if (mNetworkInfo != null) {
                    return mNetworkInfo.isAvailable();
                }
            }
            return false;
        }
    
    
        /**
         * 判断WIFI网络是否可用
         * @param context
         * @return
         */
        public static boolean isWifiConnected(Context context) {
            if (context != null) {
                ConnectivityManager mConnectivityManager = (ConnectivityManager) context
                        .getSystemService(Context.CONNECTIVITY_SERVICE);
                NetworkInfo mWiFiNetworkInfo = mConnectivityManager
                        .getNetworkInfo(ConnectivityManager.TYPE_WIFI);
                if (mWiFiNetworkInfo != null) {
                    return mWiFiNetworkInfo.isAvailable();
                }
            }
            return false;
        }
    
    
        /**
         * 判断MOBILE网络是否可用
         * @param context
         * @return
         */
        public static boolean isMobileConnected(Context context) {
            if (context != null) {
                ConnectivityManager mConnectivityManager = (ConnectivityManager) context
                        .getSystemService(Context.CONNECTIVITY_SERVICE);
                NetworkInfo mMobileNetworkInfo = mConnectivityManager
                        .getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
                if (mMobileNetworkInfo != null) {
                    return mMobileNetworkInfo.isAvailable();
                }
            }
            return false;
        }
    
    
        /**
         * 获取当前网络连接的类型信息
         * @param context
         * @return
         */
        public static int getConnectedType(Context context) {
            if (context != null) {
                ConnectivityManager mConnectivityManager = (ConnectivityManager) context
                        .getSystemService(Context.CONNECTIVITY_SERVICE);
                NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
                if (mNetworkInfo != null && mNetworkInfo.isAvailable()) {
                    return mNetworkInfo.getType();
                }
            }
            return -1;
        }
    
    
        /**
         * 获取当前的网络状态 :没有网络0:WIFI网络1:3G网络2:2G网络3
         *
         * @param context
         * @return
         */
        public static int getAPNType(Context context) {
            int netType = 0;
            ConnectivityManager connMgr = (ConnectivityManager) context
                    .getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
            if (networkInfo == null) {
                return netType;
            }
            int nType = networkInfo.getType();
            if (nType == ConnectivityManager.TYPE_WIFI) {
                netType = 1;// wifi
            } else if (nType == ConnectivityManager.TYPE_MOBILE) {
                int nSubType = networkInfo.getSubtype();
                TelephonyManager mTelephony = (TelephonyManager) context
                        .getSystemService(Context.TELEPHONY_SERVICE);
                if (nSubType == TelephonyManager.NETWORK_TYPE_UMTS
                        && !mTelephony.isNetworkRoaming()) {
                    netType = 2;// 3G
                } else {
                    netType = 3;// 2G
                }
            }
            return netType;
        }
    }
    
    public class ZipUtils {
        private static final int BUFF_SIZE = 1024;
    
        /**
         * @param zos           压缩流
         * @param parentDirName 父目录
         * @param file          待压缩文件
         * @param buffer        缓冲区
         *                      URL:http://www.bianceng.cn/OS/extra/201609/50420.htm
         * @return 只要目录中有一个文件压缩失败,就停止并返回
         */
        private static boolean zipFile(ZipOutputStream zos, String parentDirName, File file, byte[] buffer) {
            String zipFilePath = parentDirName + file.getName();
            if (file.isDirectory()) {
                zipFilePath += File.separator;
                for (File f : file.listFiles()) {
                    if (!zipFile(zos, zipFilePath, f, buffer)) {
                        return false;
                    }
                }
                return true;
            } else {
                try {
                    BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
                    ZipEntry zipEntry = new ZipEntry(zipFilePath);
                    zipEntry.setSize(file.length());
                    zos.putNextEntry(zipEntry);
                    while (bis.read(buffer) != -1) {
                        zos.write(buffer);
                    }
                    bis.close();
                    return true;
                } catch (FileNotFoundException ex) {
                    ex.printStackTrace();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
                return false;
            }
        }
    
        /**
         * @param srcPath 待压缩的文件或目录
         * @param dstPath 压缩后的zip文件
         * @return 只要待压缩的文件有一个压缩失败就停止压缩并返回(等价于windows上直接进行压缩)
         */
        public static boolean zipFile(String srcPath, String dstPath) {
            File srcFile = new File(srcPath);
            if (!srcFile.exists()) {
                return false;
            }
            byte[] buffer = new byte[BUFF_SIZE];
            try {
                ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(dstPath));
                boolean result = zipFile(zos, "", srcFile, buffer);
                zos.close();
                return result;
            } catch (FileNotFoundException ex) {
                ex.printStackTrace();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            return false;
        }
    
        /**
         * @param srcPath 待解压的zip文件
         * @param dstPath zip解压后待存放的目录
         * @return 只要解压过程中发生错误,就立即停止并返回(等价于windows上直接进行解压)
         */
        public static boolean unzipFile(String srcPath, String dstPath) {
            if (TextUtils.isEmpty(srcPath) || TextUtils.isEmpty(dstPath)) {
                return false;
            }
            File srcFile = new File(srcPath);
            if (!srcFile.exists() || !srcFile.getName().toLowerCase(Locale.getDefault()).endsWith("zip")) {
                return false;
            }
            File dstFile = new File(dstPath);
            if (!dstFile.exists() || !dstFile.isDirectory()) {
                dstFile.mkdirs();
            }
            try {
                ZipInputStream zis = new ZipInputStream(new FileInputStream(srcFile));
                BufferedInputStream bis = new BufferedInputStream(zis);
                ZipEntry zipEntry = null;
                byte[] buffer = new byte[BUFF_SIZE];
                if (!dstPath.endsWith(File.separator)) {
                    dstPath += File.separator;
                }
                while ((zipEntry = zis.getNextEntry()) != null) {
                    String fileName = dstPath + zipEntry.getName();
                    File file = new File(fileName);
                    File parentDir = file.getParentFile();
                    if (!parentDir.exists()) {
                        parentDir.mkdirs();
                    }
                    FileOutputStream fos = new FileOutputStream(file);
                    while (bis.read(buffer) != -1) {
                        fos.write(buffer);
                    }
                    fos.close();
                }
                bis.close();
                zis.close();
                return true;
            } catch (FileNotFoundException ex) {
                ex.printStackTrace();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            return false;
        }
    }
    
    展开全文
  • 手机处于通话状态时,开启录音机 获取MediaRecorder对象,通过new出来 调用MediaRecorder对象的setAudioSource()方法,设置音频源, 参数:MediaRecorder.AudioSource.MIC,参数是麦克风,默认只支持单向录音 ...
  • 这四种状态中,比如手机处于关机状态时,就不能进行通话,只能进行开机;手机没有信号的时候,就不能进行打电话,只能进行关机;当手机出于开机状态的时候,手机可以没有信号也可以关机等。 所以手机不同的状态就会...
  • 摘要:本文介绍了Android手机的基础信息的获取方法和手机基础业务语音和短消息的开发方法,基础... 具备移动通信基础知识的读者们都知道只要手机处于开机的状态无论是否处于通话状态手机和移动网络会进行很多信息交互在非
  • 近日,网传iPhone用户都接到了陌生邮箱账户打来的Facetime视频通话,接通后对方处于黑漆漆的状态,只有自己的图像呈现在手机屏幕里,感到有些莫名奇妙。目前,腾讯手机管家安全团队已经接到用户的相关举报,经验证...
  • 昨晚,在QQ上收到嫂子的留言呼叫,我心里一紧:不好,家里担心我了……因为前不久手机丢了,这段时间一直处于没有手机状态,想想自己最近跟别人没什么业务上的来往,所以就没急着买手机,一直到现在。恰恰忘了父母与...
  • 手机串口 at 指令集

    2009-09-28 16:02:09
    例如,用AT+CMGS命令发送短消息时,如果此时正好手机处于振铃或通话状态,就会返回一个"+CMS ERROR"。所以,应当在发送命令后,检测手机的响应,失败后重发。而且,因为只有一个通信端口,发送和接收不可能同时进行...
  • GSM中唯一不要求建立端-端业务路径的业务就是短消息(亦称为短信),即使移动台已处于通话状态下仍可进行消息传输。 SMS:Short Message Service,即短消息服务。SMS主要发送的内容是文本格式。 EMS:Enhanced ...
  • 若一MS处于激活且空闲状态,客户A 要建立一个呼叫,他只要拨被叫B 客户号码,再按“拨号”键,MS便开始启动程序。 首先,MS通过随机接入控制信道(RACH)向网路发第一条消息,即接入请求消息,MSC会分配它一专用...
  • 常用系统测试方法

    2021-03-23 15:53:41
    常用系统测试方法软件测试系统测试常用的方法有:多任务测试、临界测试、中断测试、等价划分测试多任务测试多任务测试是指在非idle状态下,测试对象处于工作状态时,有新的事件发生,如手机进行通话时有短信进行,...
  • 系统测试常用测试方法软件测试系统测试一般采取...测试对象处于工作状态时,有新的事件发生,如手机进行通话时有短信进行,手机有电话呼入,这种情况就是“多任务” Eg:手机项目中,查看短信时,有来电时。。。 备注
  • 软件系统测试常用方法软件测试系统测试一般采取...测试对象处于工作状态时,有新的事件发生,如手机进行通话时有短信进行,手机有电话呼入,这种情况就是“多任务” Eg:手机项目中,查看短信时,有来电时。。。 备
  • 舞在刀尖

    2005-08-06 16:46:00
    小人鱼在刀尖上痛快地舞着,柔嫩的双脚被锋利的刀锋毫不留情地划下...”手机一直处于通话状态,我想,你是打给她,还是她呢?我有一丝的失望,因为,你忘记了我的存在。。。月仍是昨日之华,人却已远去,可是一切在回眸
  • 1.当手机处于来电状态,启动监听服务,对来电进行监听录音。 2.设置电话黑名单,当来电是黑名单电话,则直接挂断。  当拨打电话或电话状态发生改变时,系统就会发出有序广播,因此我们可以使用BordercastReceiver...
  • Android中,Activity的级别永完都没有来电这么高级别,因为手机最主要的功能,还是用来通话。 关于Android中的进程级别: 1、foreground process 正处于activity resume状态处于bound服务交互的状态 正...
  • “关机窃听”-- 病毒分析报告

    万次阅读 2014-12-23 10:01:49
    在今年10月份首届GeekPwn大赛上...该病毒通过Hook系统shutdown方法实现关机拦截,当用户关机时弹出自定义黑色界面,使手机处于“假关机”状态;后台窃取用户短信、联系人、通话记录、位置信息、通话录音,上传到服务器
  • UML应用题

    千次阅读 2020-06-01 21:05:03
    UML应用题 某学校领书的工作流程为:学生班长填写领书单,班主任审查后签名,然后班长拿领书单到书库领书。 书库保管员审查领书单是否有班主任签名,填写是否正确等...如果呼叫成动,即电活接通,手机就处 于通话状态
  • 业务分析:当app 处于 后台状态下(按home键)接到socket 消息或者推送消息 然后 直接从后台 弹出界面。 最终效果:很多 新版(Android Q)、小米等手机 弹出不相关界面。测试和产品 组 要求修复。 经过探索发现 ...
  • 在某县的路测中,因只有一部测试手机,而要同时进行拨测及路测工作。因此采用了如下的工作方式: 在车上进行路测,来到基站附近时,在“测试记录”中选择...ANT Pilot处于工作状态时,如果需要拔出测试手机进行拨测,
  • 业务分析:当app 处于 后台状态下(按home键)接到socket 消息或者推送消息 然后 直接从后台 弹出界面。 最终效果:很多 新版(Android Q)、小米等手机 弹出不相关界面。测试和产品 组 要求修复。 经过探索发现 大...
  • 比如,手机大部分时间都处于等待呼叫的状态中,实际通话的时间相当少。另一方面,MP3播放器通常不是开机处于激活运行状态,就是处于关断状态。其它系统、线路供电系统以及便携式系统,都有着不同的待机功耗分布和激
  • IP回拨业务,因为服务的特殊性,主叫(用户)方也是处于接听状态,只要是单向收费的手机,基本通话费就是0分。那么使用IP回拨业务来打电话,不管长途、市话,话费就非常低廉,竞争优势明显。 系统概念 Ø ...
  • 前言 IP回拨业务,因为服务的特殊性,主叫(用户)方也是处于接听状态,只要是单向收费的手机,基本通话费就是0分。那么使用IP回拨业务来打电话,不管长途、市话,话费就非常低廉,竞争优势明显。 系统概念 ? ...

空空如也

空空如也

1 2 3
收藏数 52
精华内容 20
关键字:

手机处于通话状态