美文网首页问题研究
Android 高版本中无法在后台震动 Ignoring inc

Android 高版本中无法在后台震动 Ignoring inc

作者: 暮雨沉沦 | 来源:发表于2019-11-20 20:18 被阅读0次

    有用户反馈在Android 10上,app到后台之后无法震动,调试后发现有一行红色的提示

    VibratorService: Ignoring incoming vibration as process with uid = 10054 is background, usage = USAGE_UNKNOWN
    

    调用震动的代码是这样:

      Vibrator mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
       long[] patern = {0,1000,1000};
       mVibrator.vibrate(patern, 1);
    

    本来好好的呀,咋就突然不行了?
    我们去找找这个类 VibratorService。先去 http://androidxref.com 看看,发现没有10.0的源码,那就先找找9.0的。我们发现了它:/frameworks/base/services/core/java/com/android/server/VibratorService.java
    然而仔细搜索并没有"background"字样,说明确实10.0有修改,9.0并不同。androidxref确实年久失修啊,只更新到 2018-08-11 。
    也可以去这里看代码:http://aospxref.com/android-10.0.0_r2/xref/frameworks/base/

    我们找了一个社区https://www.androidos.net.cn/android/10.0.0_r6/xref/frameworks/base/services/core/java/com/android/server
    确实有10.0代码,同样的目录下找到它 VibratorService,搜索"background",只有一个结果:

     public void vibrate(int uid, String opPkg, VibrationEffect effect, int usageHint, String reason,
                IBinder token) {
               。。。省略代码
                    Vibration vib = new Vibration(token, effect, usageHint, uid, opPkg, reason);
                    if (mProcStatesCache.get(uid, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND)
                            > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
                            && !vib.isNotification() && !vib.isRingtone() && !vib.isAlarm()) {
                        Slog.e(TAG, "Ignoring incoming vibration as process with"
                                + " uid = " + uid + " is background,"
                                + " usage = " + AudioAttributes.usageToString(vib.usageHint));
                        return;
                    }
                       。。。省略代码
        }
    

    分析下:mProcStatesCache存储的是整形的SparseArray,在启动service是会注册监听ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE,
    ActivityManager.PROCESS_STATE_UNKNOWN,然后保存和移除状态,应该是保存了app当前的状态,大于ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND就是比前台状态优先级低的状态了,且不是isNotification&&不是isRingtone&&不是isAlarm,就报错了。

    看看这几个判断的方法:

     private static boolean isNotification(int usageHint) {
            switch (usageHint) {
                case AudioAttributes.USAGE_NOTIFICATION:
                case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
                case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
                case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
                    return true;
                default:
                    return false;
            }
        }
    
        private static boolean isRingtone(int usageHint) {
            return usageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
        }
    
        private static boolean isAlarm(int usageHint) {
            return usageHint == AudioAttributes.USAGE_ALARM;
        }
    

    就是说要加usage了,而且mVibrator.vibrate(pattern, 1, audioAttributes)方法在低版本不存在,于是我们代码改成这样:

     Vibrator mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
       long[] patern = {0,1000,1000};
        AudioAttributes audioAttributes = null;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                audioAttributes = new AudioAttributes.Builder()
                        .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                        .setUsage(AudioAttributes.USAGE_ALARM) //key
                        .build();
                mVibrator.vibrate(pattern, 1, audioAttributes);
            }else {
                mVibrator.vibrate(pattern, 1);
            }
    

    又可以愉快地震动啦~~~
    其实这个setUsage(AudioAttributes.USAGE_ALARM)可以设置成USAGE_NOTIFICATION_RINGTONE或者USAGE_NOTIFICATION应该都可以。

    相关文章

      网友评论

        本文标题:Android 高版本中无法在后台震动 Ignoring inc

        本文链接:https://www.haomeiwen.com/subject/ztkaictx.html