Android 高版本中無法在后臺震動 Ignoring incoming vibration

有用戶反饋在Android 10上,app到后臺之后無法震動,調(diào)試后發(fā)現(xiàn)有一行紅色的提示

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

調(diào)用震動的代碼是這樣:

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

本來好好的呀,咋就突然不行了?
我們?nèi)フ艺疫@個類 VibratorService。先去 http://androidxref.com 看看,發(fā)現(xiàn)沒有10.0的源碼,那就先找找9.0的。我們發(fā)現(xiàn)了它:/frameworks/base/services/core/java/com/android/server/VibratorService.java
然而仔細(xì)搜索并沒有"background"字樣,說明確實10.0有修改,9.0并不同。androidxref確實年久失修啊,只更新到 2018-08-11 。
也可以去這里看代碼:http://aospxref.com/android-10.0.0_r2/xref/frameworks/base/

我們找了一個社區(qū)https://www.androidos.net.cn/android/10.0.0_r6/xref/frameworks/base/services/core/java/com/android/server
確實有10.0代碼,同樣的目錄下找到它 VibratorService,搜索"background",只有一個結(jié)果:

 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是會注冊監(jiān)聽ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE,
ActivityManager.PROCESS_STATE_UNKNOWN,然后保存和移除狀態(tài),應(yīng)該是保存了app當(dāng)前的狀態(tài),大于ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND就是比前臺狀態(tài)優(yōu)先級低的狀態(tài)了,且不是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)可以設(shè)置成USAGE_NOTIFICATION_RINGTONE或者USAGE_NOTIFICATION應(yīng)該都可以。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容