En Android 11, las llamadas entrantes se muestran por defecto como notificaciones flotantes en la parte superior de la pantalla. Para implementar una pantalla completa al recibir llamadas, se requiere modificar el flujo de notificaciones en la aplicación de marcador:
// packages/apps/Dialer/java/com/android/incallui/StatusBarNotifier.java
private boolean iniciarPantallaCompleta = true;
@RequiresPermission(Manifest.permission.READ_PHONE_STATE)
private void actualizarNotificacionLlamada() {
LogUtil.d("StatusBarNotifier.actualizarNotificacionLlamada", "");
final DialerCall llamadaActual = obtenerLlamadaActiva(CallList.getInstance());
if (llamadaActual == null || llamadaActual.fueRechazada()) {
iniciarPantallaCompleta = true;
cancelarNotificacion();
return;
}
mostrarNotificacion(llamadaActual);
if (iniciarPantallaCompleta) {
contexto.startActivity(InCallActivity.crearIntent(
contexto,
false,
false,
true // Modo pantalla completa
));
iniciarPantallaCompleta = false;
}
}
El comportamiento de las notificaciones depende de dos factores: la prioridad de la notificación y el canal de notificación. En Android 11, los canales con IMPORTANCE_MAX pueden mostrar notificaciones flotantse. Para evitar esto, se debe redirigir las llamadas entrantes al canal de llamada en curso:
// packages/apps/Dialer/java/com/android/dialer/notification/NotificationChannelManager.java
private static void configurarCanalLlamadaEntrante(@NonNull Context contexto) {
NotificationChannel canal = new NotificationChannel(
NotificationChannelId.LLAMADA_ENTRANTE,
contexto.getText(R.string.canal_notif_llamada_entrante),
NotificationManager.IMPORTANCE_LOW // Reducir prioridad
);
// Configuración adicional del canal
}
// packages/apps/Dialer/java/com/android/incallui/InCallPresenter.java
private void construirNotificacion(CallList lista, DialerCall llamada) {
switch (tipoNotificacion) {
case NOTIFICACION_LLAMADA_ENTRANTE:
if (BuildCompat.esOreoSuperior()) {
constructor.setChannelId(NotificationChannelId.LLAMADA_EN_CURSO);
}
break;
// Otros casos
}
}
Para mejorar la sensibilidad de los gestos de deslizamiento en dispositivos MTK, se deben ajustar los umbrales en el gestor de toque. Los parámetros críticos son:
- UMBRAL_RESPUESTA_DP: Distancai mínima para considerar una respuesta (reducir de 150 a 100)
- PROGRESO_RECENTER: Porcentaje mínimo para validar el gesto (ajustar de 0.8f a 0.7f)
- UMBRAL_FALSOS_TOQUES: Tolerancia para descartar falsos toques (reducir de 40 a 30)
// packages/apps/Dialer/java/com/android/incallui/gesture/GestureHandler.java
// Ajuste de sensibilidad para respuesta de llamadas
private static final int UMBRAL_RESPUESTA_DP = 100;
private static final float PROGRESO_RECENTER = 0.7f;
private static final int UMBRAL_FALSOS_TOQUES = 30;
private void procesarToque(MotionEvent evento) {
// Lógica optimizada para detección de gestos
if (Math.abs(desplazamientoY) > UMBRAL_FALSOS_TOQUES) {
float velocidad = calcularVelocidad();
if (velocidad > obtenerMinimaVelocidad() * 0.8f) {
ejecutarAccionSegunGesto();
}
}
}
En la implementación del gesto, se modifica la lógica de validación para permitir respuestsa más sensibles:
private boolean validarGesto(float progresoInicial) {
return progresoInicial <= 0.15 &&
Math.abs(desplazamientoTotal) > UMBRAL_FALSOS_TOQUES;
}
Como alternativa para personalizar aún más el comportamiento, se puede interceptar el botón de inicio a nivel de framework:
// frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
@Override
public long interceptKeyBeforeDispatching(WindowState ventana, KeyEvent evento) {
if (evento.getKeyCode() == KeyEvent.KEYCODE_HOME && !evento.isDown()) {
if (aplicacionEnPrimerPlano("com.ejemplo.dialer")) {
return -1; // Bloquear acción predeterminada
}
}
return super.interceptKeyBeforeDispatching(ventana, evento);
}