android 实现一键静音功能

最近在android5.1上面做一个功能,类似苹果的一键静音功能。山寨大国,一直模仿,但从未超越,别人做什么,砸门跟着做。下面就来看看android究竟怎么实现这个功能呢?
刚开始我也不知到怎么做,怎么办呢?只好想方设法的找线索,首先先把按键驱动实现了,上层能读到按键事件后,那就好办了,好,那我们就先实现按键驱动。
高通源码里面已经实现了按键的驱动,只需要添加我们所需的节点就好了,下面以具体代码来说明

第一步:按键驱动
1.驱动代码
kernel\drivers\switch\switch_gpio.c
kernel\drivers\switch\switch_class.c
2.设备节点
kernel\arch\arm64\boot\dts\chinachip\msm8916-mtp.dtsi

    gpio_swtich{
        compatible = "qcom,gpio-switch";
      pinctrl-names = "default","sleep";
        pinctrl-0 = <&ringerkey_default>;
        pinctrl-1 = <&ringerkey_sleep>;
        interrupt-parent = <&msm_gpio>;
        interrupts = <36 0x2003>;       
        switch-name = "ringerkey";
        switch-gpio = <&msm_gpio 36 0x2003>;
    };

kernel\arch\arm64\boot\dts\chinachip\msm8916-pinctrl.dtsi

 ringerkey_int_pin {
            qcom,pins = <&gp 36>;
            qcom,pin-func = <0>;
            qcom,num-grp-pins = <1>;
            label = "ringerkey-irq";
            ringerkey_default: ringerkey_default {
                drive-strength = <6>;
                bias-pull-up;
            };
            ringerkey_sleep: ringerkey_sleep {
                drive-strength = <2>;
                bias-pull-down;
            };
        };

到此,kernel部分就完成了。
第二部分:应用
在不知道怎么加的情况下,那就搜索中文字,通过logcat分析,这部分的代码在framework里面,frameworks\base\packages\SystemUI\src\com\android\systemui\volume\。
android铃声模式分为三种, 在AudioManager.java里有定义,
public static final int RINGER_MODE_SILENT = 0; //静音模式
public static final int RINGER_MODE_VIBRATE = 1; // 振动模式
public static final int RINGER_MODE_NORMAL = 2; // 一般模式
android控制静音功能分为两部分,一部分是内部控制,一部分外部控制,但是这两部分控制逻辑是不一样的,当内部发送一个RINGER_MODE_SILENT,会调用ZenModeHelper.onSetRingerModeInternal()方法,系统设置的是全部静音,当外部发送一个RINGER_MODE_SILENT,会调用ZenModeHelper.onSetRingerModeExternal()方法,系统设置的是优先模式,那么我们要设置响铃模式,可以调用AudioManager.setRingerMode()方法设置。

在DockObserver.java里面添加自己的服务,

import android.media.AudioManager;
      private static final String Ringer_UEVENT_MATCH = "DEVPATH=/devices/virtual/switch/ringerkey";
      private static final String Ringer_STATE_MATCH = "/sys/class/switch/ringerkey/state";
    public static final int MSG_RINGER_MODE_SILENT = 0;
    public static final int MSG_RINGER_MODE_NORMAL = 2;

 private final Handler mHandler = new Handler(true /*async*/) {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            /*    case MSG_DOCK_STATE_CHANGED:
                    handleDockStateChange();
                    mWakeLock.release();
                    break;*/
                case MSG_RINGER_MODE_SILENT:
                     Slog.i(TAG, "RINGER_MODE_SILENT: ");
                     RingerModeSwitch(AudioManager.RINGER_MODE_SILENT);
                     break;
                case MSG_RINGER_MODE_NORMAL:
                     Slog.i(TAG, "RINGER_MODE_NORMAL ");
                     RingerModeSwitch(AudioManager.RINGER_MODE_NORMAL);
                     break;
                case MSG_CABLE_OFF_CHANGED:
                     Slog.i(TAG, "MSG_CABLE_OFF_CHANGED: ");
                     NoticCableSwitch(true);
                     break;
                case MSG_CHARGER_OFF_CHANGED:
                     Slog.i(TAG, "MSG_CHARGER_OFF_CHANGED: ");
                     NoticChargerSwitch(true);
                     break;
            }
        }
    };


   private final UEventObserver mObserver = new UEventObserver() {
        @Override
        public void onUEvent(UEventObserver.UEvent event) {
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                Slog.v(TAG, "Dock UEVENT: " + event.toString());
            }

         Slog.v(TAG, "Dock UEVENT: " + event.toString());
             String misc_name = event.get("DEVNAME");
             if(misc_name!=null&&misc_name.equals("mpu6880_collision")){
                  Slog.v(TAG, "Dock UEVENT: mpu6880_collision");
                  mHandler.sendEmptyMessage(MSG_CABLE_OFF_CHANGED);
                  return;
             }
            String switch_name = event.get("SWITCH_NAME");
            String switch_state = event.get("SWITCH_STATE");
               Slog.e(TAG, "switch_name " + switch_name);
               Slog.e(TAG, "switch_state " + switch_state);
               if(switch_name.equals("ringerkey")){
                 int newState = Integer.parseInt(switch_state);
                 if(newState==1){
                     mHandler.sendEmptyMessage(MSG_RINGER_MODE_SILENT);
                 }else{
                     mHandler.sendEmptyMessage(MSG_RINGER_MODE_NORMAL);
                 }
                 return;
               }else if(switch_name.equals("charger_cable")){
                    int mState = Integer.parseInt(switch_state);
                    if(mState==0)
                     mHandler.sendEmptyMessage(MSG_CHARGER_OFF_CHANGED);
                    Slog.e(TAG, "return ");
                    return;
               }
            try {
                synchronized (mLock) {
                    setActualDockStateLocked(Integer.parseInt(event.get("SWITCH_STATE")));
                }
            } catch (NumberFormatException e) {
                Slog.e(TAG, "Could not parse switch state from event " + event);
            }
        }
    };

private void RingerModeSwitch(int ringermode){
        Slog.i(TAG, "NoticeRingerSwitch"+ringermode);
        mAudioManager.setRingerMode(ringermode);
        }

下面我们就来分析下,两种方法:

public int onSetRingerModeInternal(int ringerModeOld, int ringerModeNew, String caller,
            int ringerModeExternal) {
        final boolean isChange = ringerModeOld != ringerModeNew;

        int ringerModeExternalOut = ringerModeNew;

        int newZen = -1;
        switch (ringerModeNew) {
            case AudioManager.RINGER_MODE_SILENT:
                if (isChange) {
                    if (mZenMode != Global.ZEN_MODE_NO_INTERRUPTIONS) {
                        newZen = Global.ZEN_MODE_NO_INTERRUPTIONS;
                    }
                }
                break;
            case AudioManager.RINGER_MODE_VIBRATE:
            case AudioManager.RINGER_MODE_NORMAL:
                if (isChange && ringerModeOld == AudioManager.RINGER_MODE_SILENT
                        && mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS) {
                    newZen = Global.ZEN_MODE_OFF;
                } else if (mZenMode != Global.ZEN_MODE_OFF) {
                    ringerModeExternalOut = AudioManager.RINGER_MODE_SILENT;
                }
                break;
        }
        if (newZen != -1) {
            setZenMode(newZen, "ringerModeInternal", false /*setRingerMode*/);
        }

        if (isChange || newZen != -1 || ringerModeExternal != ringerModeExternalOut) {
            ZenLog.traceSetRingerModeInternal(ringerModeOld, ringerModeNew, caller,
                    ringerModeExternal, ringerModeExternalOut);
        }
        return ringerModeExternalOut;
    }
    public int onSetRingerModeExternal(int ringerModeOld, int ringerModeNew, String caller,
            int ringerModeInternal) {
        int ringerModeInternalOut = ringerModeNew;
        final boolean isChange = ringerModeOld != ringerModeNew;
        final boolean isVibrate = ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE;

        int newZen = -1;
        switch (ringerModeNew) {
            case AudioManager.RINGER_MODE_SILENT:
                if (isChange) {
                    if (mZenMode == Global.ZEN_MODE_OFF &&
                        mContext.getResources().getBoolean(com.android.internal.R.bool.config_setZenModeWhenSilentModeOn))
                    {
                        newZen = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
                    }
                    ringerModeInternalOut = isVibrate ? AudioManager.RINGER_MODE_VIBRATE
                            : AudioManager.RINGER_MODE_NORMAL;
                } else {
                    ringerModeInternalOut = ringerModeInternal;
                }
                break;
            case AudioManager.RINGER_MODE_VIBRATE:
            case AudioManager.RINGER_MODE_NORMAL:
                if (mZenMode != Global.ZEN_MODE_OFF) {
                    newZen = Global.ZEN_MODE_OFF;
                }
                break;
        }
        if (newZen != -1) {
            setZenMode(newZen, "ringerModeExternal", false /*setRingerMode*/);
        }

        ZenLog.traceSetRingerModeExternal(ringerModeOld, ringerModeNew, caller, ringerModeInternal,
                ringerModeInternalOut);
        return ringerModeInternalOut;
    }

比较这两个函数,当isChange为真的时候,newZen 的值是不一样的,这个地方就是就是设下去的方法。要想设置成苹果静音键的功能,在来电过程中也能静音控制,那就需要修改onSetRingerModeExternal()里的方法,

 case AudioManager.RINGER_MODE_SILENT:
                if (isChange) {
                    if (mZenMode == Global.ZEN_MODE_OFF &&
                        mContext.getResources().getBoolean(com.android.internal.R.bool.config_setZenModeWhenSilentModeOn))
                    {
                        newZen = Global.ZEN_MODE_NO_INTERRUPTIONS;
                    }
                    ringerModeInternalOut = isVibrate ? AudioManager.RINGER_MODE_VIBRATE
                            : AudioManager.RINGER_MODE_SILENT;
                } else {
                    ringerModeInternalOut = ringerModeInternal;
                }
                break;

这样修改后,就实现了苹果一样的功能了。

你可能感兴趣的:(Android开发)