diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 33fc9c3..5752105 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -8,6 +8,7 @@ + = Build.VERSION_CODES.R) { - getWindow().setDecorFitsSystemWindows(false); - WindowInsetsController wic = getWindow().getInsetsController(); - if (wic != null) { - wic.hide(WindowInsets.Type.statusBars() | WindowInsets.Type.navigationBars()); - wic.setSystemBarsBehavior(WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE); - } - } else { - //noinspection deprecation - getWindow().getDecorView().setSystemUiVisibility( - View.SYSTEM_UI_FLAG_FULLSCREEN - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); + // 延伸到挖孔/刘海区域(API 28+) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + WindowManager.LayoutParams lp = getWindow().getAttributes(); + lp.layoutInDisplayCutoutMode = + WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; + getWindow().setAttributes(lp); } + // 隐藏状态栏和导航栏(immersive sticky,已废弃但所有版本兼容) + //noinspection deprecation + getWindow().getDecorView().setSystemUiVisibility( + View.SYSTEM_UI_FLAG_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); + String caller = getIntent().getStringExtra("caller"); int ringDuration = getIntent().getIntExtra("ringDuration", 30); boolean autoAccept = getIntent().getBooleanExtra("auto_accept", false); if (caller == null || caller.isEmpty()) caller = "Unknown"; + // 全屏模式由 setFullScreenIntent 触发,Activity 起来后立即取消通知,下拉栏不残留 + IncomingCallNotificationHelper.cancel(this); + // 通知栏 Answer 按钮直接触发:跳过 UI,deliver accept 后进 app if (autoAccept) { resultDelivered = true; @@ -143,7 +153,7 @@ public class IncomingCallActivity extends Activity { FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT); rowLp.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; - rowLp.bottomMargin = dp(48); + rowLp.bottomMargin = dp(78); rowLp.leftMargin = dp(13); rowLp.rightMargin = dp(13); btnRow.setLayoutParams(rowLp); @@ -154,6 +164,8 @@ public class IncomingCallActivity extends Activity { android.R.drawable.ic_menu_close_clear_cancel); btnDecline.setOnClickListener(v -> { resultDelivered = true; + stopRingtone(); + stopVibrate(); IncomingCallNotificationHelper.cancel(this); IncomingCallNotificationHelper.deliverCallResult(this, "decline"); launchMainApp(finalCaller); @@ -169,6 +181,8 @@ public class IncomingCallActivity extends Activity { ImageView btnAccept = makeCircleBtn(0xFF17b834, android.R.drawable.ic_menu_call); btnAccept.setOnClickListener(v -> { resultDelivered = true; + stopRingtone(); + stopVibrate(); IncomingCallNotificationHelper.cancel(this); IncomingCallNotificationHelper.deliverCallResult(this, "accept"); launchMainApp(finalCaller); @@ -178,12 +192,18 @@ public class IncomingCallActivity extends Activity { root.addView(btnRow); + // ── 铃声 + 震动 ──────────────────────────────────────────────────────── + startRingtone(); + startVibrate(ringDuration); + // ── 倒计时自动挂断 ──────────────────────────────────────────────────── countDown = new CountDownTimer(ringDuration * 1000L, 1000) { @Override public void onTick(long ms) {} @Override public void onFinish() { if (!resultDelivered) { resultDelivered = true; + stopRingtone(); + stopVibrate(); IncomingCallNotificationHelper.cancel(IncomingCallActivity.this); IncomingCallNotificationHelper.deliverCallResult( IncomingCallActivity.this, "decline"); @@ -224,9 +244,65 @@ public class IncomingCallActivity extends Activity { return Math.round(dp * getResources().getDisplayMetrics().density); } + private Ringtone ringtone; + private Vibrator vibrator; + + private void startRingtone() { + try { + Uri uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE); + if (uri == null) uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); + ringtone = RingtoneManager.getRingtone(getApplicationContext(), uri); + if (ringtone == null) return; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + ringtone.setLooping(true); + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + ringtone.setAudioAttributes(new AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE) + .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) + .build()); + } else { + //noinspection deprecation + ringtone.setStreamType(AudioManager.STREAM_RING); + } + ringtone.play(); + } catch (Exception e) { + android.util.Log.w("IncomingCallActivity", "startRingtone: " + e.getMessage()); + } + } + + private void stopRingtone() { + if (ringtone != null) { + ringtone.stop(); + ringtone = null; + } + } + + @SuppressWarnings("deprecation") + private void startVibrate(int durationSec) { + vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE); + if (vibrator == null || !vibrator.hasVibrator()) return; + // 来电节奏:0ms 延迟,500ms 振,500ms 停,循环 + long[] pattern = { 0, 500, 500 }; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + vibrator.vibrate(VibrationEffect.createWaveform(pattern, 0)); + } else { + vibrator.vibrate(pattern, 0); + } + } + + private void stopVibrate() { + if (vibrator != null) { + vibrator.cancel(); + vibrator = null; + } + } + @Override protected void onDestroy() { if (countDown != null) countDown.cancel(); + stopRingtone(); + stopVibrate(); // back 键或系统杀掉时兜底触发 decline if (!resultDelivered) { resultDelivered = true;