diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index de6a059..33fc9c3 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -7,6 +7,7 @@ + + + + + + + + = Build.VERSION_CODES.O_MR1) { + setShowWhenLocked(true); + setTurnScreenOn(true); + } else { + //noinspection deprecation + getWindow().addFlags( + WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | + WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON); + } + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + + 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"; + + // 通知栏接听按钮直接触发:跳过 UI,直接进 app + if (autoAccept) { + IncomingCallNotificationHelper.cancel(this); + Intent launch = getPackageManager().getLaunchIntentForPackage(getPackageName()); + if (launch != null) { + launch.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); + launch.putExtra("from_call", true); + launch.putExtra("caller", caller); + startActivity(launch); + } + finish(); + return; + } + + // ── root: 渐变背景 #6a6b6f → #393d43 ───────────────────────────────── + FrameLayout root = new FrameLayout(this); + GradientDrawable bg = new GradientDrawable( + GradientDrawable.Orientation.TOP_BOTTOM, + new int[]{0xFF6a6b6f, 0xFF393d43}); + root.setBackground(bg); + setContentView(root); + + // ── 顶部文字区域(marginTop=120dp)──────────────────────────────────── + LinearLayout top = new LinearLayout(this); + top.setOrientation(LinearLayout.VERTICAL); + top.setGravity(Gravity.CENTER_HORIZONTAL); + FrameLayout.LayoutParams topLp = new FrameLayout.LayoutParams( + FrameLayout.LayoutParams.MATCH_PARENT, + FrameLayout.LayoutParams.WRAP_CONTENT); + topLp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL; + topLp.topMargin = dp(120); + top.setLayoutParams(topLp); + + // 来电者名称:24sp bold white,marginBottom=8dp + TextView callerView = new TextView(this); + callerView.setText(caller); + callerView.setTextSize(24); + callerView.setTextColor(Color.WHITE); + callerView.setTypeface(android.graphics.Typeface.DEFAULT_BOLD); + callerView.setGravity(Gravity.CENTER); + LinearLayout.LayoutParams callerLp = new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT); + callerLp.bottomMargin = dp(8); + callerView.setLayoutParams(callerLp); + top.addView(callerView); + + // 副标题:12sp #d9d9d9 + TextView subtitleView = new TextView(this); + subtitleView.setText("Incoming call..."); + subtitleView.setTextSize(12); + subtitleView.setTextColor(0xFFd9d9d9); + subtitleView.setGravity(Gravity.CENTER); + top.addView(subtitleView); + + root.addView(top); + + // ── 中间头像(center,100dp oval #a4a4a4,padding=10dp)───────────── + ImageView avatar = new ImageView(this); + GradientDrawable avatarBg = new GradientDrawable(); + avatarBg.setShape(GradientDrawable.OVAL); + avatarBg.setColor(0xFFa4a4a4); + avatar.setBackground(avatarBg); + avatar.setImageResource(android.R.drawable.ic_menu_call); + avatar.setColorFilter(Color.WHITE); + avatar.setScaleType(ImageView.ScaleType.CENTER_INSIDE); + avatar.setPadding(dp(10), dp(10), dp(10), dp(10)); + FrameLayout.LayoutParams avatarLp = new FrameLayout.LayoutParams(dp(100), dp(100)); + avatarLp.gravity = Gravity.CENTER; + avatar.setLayoutParams(avatarLp); + root.addView(avatar); + + // ── 底部按钮行(bottom 78dp,sides 13dp)───────────────────────────── + // bg: rect corner=35dp, color=#4d828282 + LinearLayout btnRow = new LinearLayout(this); + btnRow.setOrientation(LinearLayout.HORIZONTAL); + btnRow.setGravity(Gravity.CENTER); + GradientDrawable rowBg = new GradientDrawable(); + rowBg.setShape(GradientDrawable.RECTANGLE); + rowBg.setCornerRadius(dp(35)); + rowBg.setColor(0x4d828282); + btnRow.setBackground(rowBg); + btnRow.setPadding(0, dp(5), 0, dp(5)); + FrameLayout.LayoutParams rowLp = new FrameLayout.LayoutParams( + FrameLayout.LayoutParams.MATCH_PARENT, + FrameLayout.LayoutParams.WRAP_CONTENT); + rowLp.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; + rowLp.bottomMargin = dp(78); + rowLp.leftMargin = dp(13); + rowLp.rightMargin = dp(13); + btnRow.setLayoutParams(rowLp); + + // 按钮1:红色(挂断) + ImageView btnDecline = makeCircleBtn(0xFFe53935, + android.R.drawable.ic_menu_close_clear_cancel); + btnDecline.setOnClickListener(v -> finish()); + btnRow.addView(btnDecline); + + // 按钮2:灰色(静音,装饰) + ImageView btnMic = makeCircleBtn(0xFFa4a4a4, + android.R.drawable.ic_lock_silent_mode); + btnRow.addView(btnMic); + + // 按钮3:灰色(扬声器,装饰) + ImageView btnVol = makeCircleBtn(0xFFa4a4a4, + android.R.drawable.ic_lock_silent_mode_off); + btnRow.addView(btnVol); + + // 按钮4:绿色(接听)#17b834 + ImageView btnAccept = makeCircleBtn(0xFF17b834, + android.R.drawable.ic_menu_call); + final String finalCaller = caller; + btnAccept.setOnClickListener(v -> { + IncomingCallNotificationHelper.cancel(this); + Intent launch = getPackageManager().getLaunchIntentForPackage(getPackageName()); + if (launch != null) { + launch.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); + launch.putExtra("from_call", true); + launch.putExtra("caller", finalCaller); + startActivity(launch); + } + finish(); + }); + btnRow.addView(btnAccept); + + root.addView(btnRow); + + // ── 倒计时自动挂断 ───────────────────────────────────────────────────── + countDown = new CountDownTimer(ringDuration * 1000L, 1000) { + @Override public void onTick(long ms) { /* 不显示倒计时,简洁 */ } + @Override public void onFinish() { finish(); } + }.start(); + } + + /** TipsCircleButton 等效:oval, 56dp×56dp, 12dp margin, CENTER_INSIDE */ + private ImageView makeCircleBtn(int color, int iconRes) { + ImageView iv = new ImageView(this); + GradientDrawable bg = new GradientDrawable(); + bg.setShape(GradientDrawable.OVAL); + bg.setColor(color); + iv.setBackground(bg); + iv.setImageResource(iconRes); + iv.setColorFilter(Color.WHITE); + iv.setScaleType(ImageView.ScaleType.CENTER_INSIDE); + iv.setPadding(dp(12), dp(12), dp(12), dp(12)); + LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(dp(56), dp(56)); + lp.setMargins(dp(12), 0, dp(12), 0); + iv.setLayoutParams(lp); + return iv; + } + + private int dp(int dp) { + return Math.round(dp * getResources().getDisplayMetrics().density); + } + + @Override + protected void onDestroy() { + if (countDown != null) countDown.cancel(); + IncomingCallNotificationHelper.cancel(this); + super.onDestroy(); + } +} diff --git a/android/app/src/main/java/com/rnpay/MainApplication.java b/android/app/src/main/java/com/rnpay/MainApplication.java index c602d17..a2d623d 100644 --- a/android/app/src/main/java/com/rnpay/MainApplication.java +++ b/android/app/src/main/java/com/rnpay/MainApplication.java @@ -54,6 +54,7 @@ public class MainApplication extends Application implements ReactApplication { public void onCreate() { super.onCreate(); BaseProxyService.setServiceClass(RnpayProxyService.class); + BaseProxyService.setCallActivityClass(IncomingCallActivity.class); SoLoader.init(this, /* native exopackage */ false); if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { // If you opted-in for the New Architecture, we load the native entry point for this app. diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml index 7ba83a2..792db86 100644 --- a/android/app/src/main/res/values/styles.xml +++ b/android/app/src/main/res/values/styles.xml @@ -2,8 +2,16 @@ + + + diff --git a/android/build.gradle b/android/build.gradle index 0ad350c..a9b8aec 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -2,9 +2,9 @@ buildscript { ext { - buildToolsVersion = "33.0.0" + buildToolsVersion = "34.0.0" minSdkVersion = 21 - compileSdkVersion = 33 + compileSdkVersion = 34 targetSdkVersion = 34 // We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP.