Android 10 (Q) 问题解决记录

前言

最近在使用Pixel3测试时在Android10的系统上遇到一些疑难问题, 在此跟你们分享一下java

1. Android 10 (Q)没法接收UDP广播包的问题

在Android10上, App默认是没有接收UDP广播包的权限的, 致使一些搜索功能不可用, 具体的解决方案 须要申请MulticastLock才能够接收广播包, 代码以下:android

//获取
WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
//须要在AndroidManifest申请 CHANGE_WIFI_MULTICAST_STATE 权限, 该权限为非敏感权限, 不用动态申请
multiCastLock = wifiManager.createMulticastLock("nulticase_lock");

//请求Lock, 注意运行时只能请求一个, 反复申请会报错, 获取以后就能接收广播了
multiCastLock.acquire();

//再也不接收广播的时候须要释放lock
multiCastLock.release();
复制代码

2. Android 10 (Q) App在后台没法触发振动

当手机处于后台时, 调用振动的代码无效, 调用的代码为:bash

Vibrator mVibrator = (Vibrator) App.getInstance().getSystemService(Context.VIBRATOR_SERVICE);
long[] pattern = {100, 1000, 100, 1000};
mVibrator.vibrate(pattern, 2);
复制代码

此时看logcat上的打印为:测试

E/VibratorService: Ignoring incoming vibration as process with uid = 10323 is background, usage = USAGE_UNKNOWNui

在工程全局搜索可找到以下源码:this

//package com.android.server;
//VibratorService.java
//只摘取了部分源码

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;
}

public boolean isNotification() {
    return VibratorService.this.isNotification(usageHint);
}
    
public boolean isRingtone() {
    return VibratorService.this.isRingtone(usageHint);
}

public boolean isAlarm() {
    return VibratorService.this.isAlarm(usageHint);
}

public boolean isAlarm() {
    return VibratorService.this.isAlarm(usageHint);
}
    
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;
}

复制代码

由源码可知, 当App处于后台时且AudioAttributes不是Notification、Ringtone或者Alarm时, 请求振动的操做会被拒绝, 首先App在后台, 因此mProcStatesCache.get() 这个判断必然为ture, 那处理方案须要从usageHint来解决spa

经过查看mVibrator.vibrate()的参数会发现, 有一个构造方法为日志

public void vibrate(long[] pattern, int repeat, AudioAttributes attributes)code

正好能够传入一个AudioAttributes, 故该问题解决方案以下:server

Vibrator mVibrator = (Vibrator) App.getInstance().getSystemService(Context.VIBRATOR_SERVICE);
long[] pattern = {100, 1000, 100, 1000};
AudioAttributes audioAttributes = new AudioAttributes.Builder()
                    .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                    .setUsage(AudioAttributes.USAGE_ALARM) // 源码中isAlarm判断可经过
                    .build();
mVibrator.vibrate(pattern, 2);
复制代码

3. Android 10 (Q) 弹出通知栏, 振动无效

在Android 10上, 经过NotificationManager.notify()弹出一个通知栏, 虽然设置了振动, 可是没有效果, 查看Logcat有如下打印

E/VibratorService: Ignoring incoming vibration as process with uid = 10323 is background, usage = USAGE_UNKNOWN

如出一辙的错误日志, 由此可知在设置振动时, 没有设置AudioAttributes,解决方法在设置AudioAttributes时将其设置为Alarm便可,代码以下:

//AudioAttributes须要经过setSound来设置

//建立默认铃声, 也能够设置自定义铃声
Uri uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationChannel notificationChannel = new NotificationChannel(CHANNEL_ID,
                CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH);
        notificationChannel.enableVibration(true); //启用振动
        AudioAttributes audioAttributes = new AudioAttributes.Builder()
                .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                .setUsage(AudioAttributes.USAGE_ALARM) //关键的一行, 设置AudioAttributes为Alarm
                .build();
        notificationChannel.setSound(uri, audioAttributes);
        notifyManager.createNotificationChannel(notificationChannel);

复制代码

结语

以上是我在适配中的总结,但愿对你们的适配有所帮助,如有错误,敬请斧正。

相关文章
相关标签/搜索