吉安感知网项目-前端
罗广辉
2026-08-13 1d552a3bad95caae4af15322df28e6240b797693
uniapps/work-app/src/uni_modules/lgh-dialog/utssdk/app-android/index.uts
@@ -1,67 +1,266 @@
import Build from "android.os.Build";
import Context from "android.content.Context";
import WindowManager from "android.view.WindowManager";
import TextView from "android.widget.TextView";
import Gravity from "android.view.Gravity";
import Color from "android.graphics.Color";
import PixelFormat from "android.graphics.PixelFormat";
import Settings from "android.provider.Settings";
import { UTSAndroid } from "io.dcloud.uts";
import Build from 'android.os.Build'
import Context from 'android.content.Context'
import Intent from 'android.content.Intent'
import Settings from 'android.provider.Settings'
import { UTSAndroid } from 'io.dcloud.uts'
import BatteryManager from 'android.os.BatteryManager'
import NotificationChannel from 'android.app.NotificationChannel'
import NotificationManager from 'android.app.NotificationManager'
import Notification from 'android.app.Notification'
import PendingIntent from 'android.app.PendingIntent'
import PowerManager from 'android.os.PowerManager'
import KeyguardManager from 'android.app.KeyguardManager'
import AlertDialog from 'android.app.AlertDialog'
import DialogInterface from 'android.content.DialogInterface'
let dialogView: TextView | null = null;
// 来电通知相关常量
const CALL_CHANNEL_ID = 'incoming_call_channel'
const CALL_NOTIFICATION_ID: Int = 2001
// 拉起应用
export function openDialog(): void {
   const context = UTSAndroid.getAppContext();
   if (context == null || dialogView != null) return;
   if (Build.VERSION.SDK_INT >= 23 && !Settings.canDrawOverlays(context)) {
      console.error("无悬浮窗权限");
      return;
   }
   const wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager;
   if (wm == null) return;
   dialogView = new TextView(context);
   dialogView!.setText("系统接听页面");
   dialogView!.setTextColor(Color.WHITE);
   dialogView!.setTextSize(22.0.toFloat());
   dialogView!.setGravity(Gravity.CENTER);
   dialogView!.setBackgroundColor(Color.parseColor("#CC000000"));
   const type = Build.VERSION.SDK_INT >= 26 ? WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY : WindowManager.LayoutParams.TYPE_PHONE;
   const flags = WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS |
      WindowManager.LayoutParams.FLAG_FULLSCREEN |
      WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
      WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON |
      WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
   const params = new WindowManager.LayoutParams(
      WindowManager.LayoutParams.MATCH_PARENT,
      WindowManager.LayoutParams.MATCH_PARENT,
      type,
      flags,
      PixelFormat.TRANSLUCENT
   );
   const context = UTSAndroid.getAppContext()
   if (context == null) return
   try {
      wm.addView(dialogView, params);
      const pm = context.getPackageManager()
      const intent = pm.getLaunchIntentForPackage(context.getPackageName())
      if (intent != null) {
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
         context.startActivity(intent)
      }
   } catch (e) {
      console.error(e);
      dialogView = null;
      console.error(e)
   }
}
export function closeDialog(): void {
   if (dialogView == null) return;
// 跳到允许悬浮窗权限页面
export function allowFloat() {
   const context = UTSAndroid.getAppContext()
   if (context == null) return
   // 1. 检查悬浮窗权限 (Android 6.0+)
   const noneFloat = Build.VERSION.SDK_INT >= 23 && !Settings.canDrawOverlays(context)
   if (!noneFloat) return
   const activity = UTSAndroid.getUniActivity()
   if (activity == null) return
   AlertDialog.Builder(activity)
      .setTitle('权限提示')
      .setMessage('为了在后台收到来电时能弹出通话界面,请开启"悬浮窗"权限')
      .setPositiveButton('去设置', (_dialog : DialogInterface, _which : Int) => {
         try {
            const intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION)
            intent.setData(android.net.Uri.parse('package:' + context.getPackageName()))
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            context.startActivity(intent)
         } catch (e) {
            console.error(e)
         }
      })
      .setNegativeButton('暂不', null)
      .show()
}
// 跳到后台弹出界面权限页面(应用详情设置)
export function allowBackgroundPopup() {
  const context = UTSAndroid.getAppContext()
  if (context == null) return
  // 后台弹出界面无标准API,用悬浮窗权限作为代理判断(有悬浮窗权限通常也允许后台弹出)
  const nonePermission = Build.VERSION.SDK_INT >= 23 && !Settings.canDrawOverlays(context)
  if (!nonePermission) return
  const activity = UTSAndroid.getUniActivity()
  if (activity == null) return
  AlertDialog.Builder(activity)
    .setTitle('权限提示')
    .setMessage('为了在后台收到来电时能弹出通话界面,请开启"后台弹出界面"权限')
    .setPositiveButton('去设置', (_dialog : DialogInterface, _which : Int) => {
      try {
        const intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
        intent.setData(android.net.Uri.parse('package:' + context.getPackageName()))
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        context.startActivity(intent)
      } catch (e) {
        console.error(e)
      }
    })
    .setNegativeButton('暂不', null)
    .show()
}
// 跳到锁屏显示权限页面(通知设置)
export function allowLockScreen() {
  const context = UTSAndroid.getAppContext()
  if (context == null) return
  // 锁屏显示依赖通知权限,检查通知是否开启
  const nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
  const nonePermission = !nm.areNotificationsEnabled()
  if (!nonePermission) return
  const activity = UTSAndroid.getUniActivity()
  if (activity == null) return
  AlertDialog.Builder(activity)
    .setTitle('权限提示')
    .setMessage('为了在锁屏时能显示来电通知,请开启"锁屏显示通知"权限')
    .setPositiveButton('去设置', (_dialog : DialogInterface, _which : Int) => {
      try {
        if (Build.VERSION.SDK_INT >= 26) {
          // Android 8.0+ 跳转到应用通知设置
          const intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS)
          intent.putExtra(Settings.EXTRA_APP_PACKAGE, context.getPackageName())
          intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
          context.startActivity(intent)
        } else {
          // 低版本跳转到应用详情
          const intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
          intent.setData(android.net.Uri.parse('package:' + context.getPackageName()))
          intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
          context.startActivity(intent)
        }
      } catch (e) {
        console.error(e)
      }
    })
    .setNegativeButton('暂不', null)
    .show()
}
/**
 * 获取电池电量百分比
 *
 * uni-app项目中调用示例:
 * import { getBatteryCapacity } from "@/uni_modules/lgh-getbatteryinfo"
 * const capacity = getBatteryCapacity()
 * console.log('电池电量:', capacity)
 */
export function getBatteryCapacity(): string {
   // 获取android系统 application上下文
   const context = UTSAndroid.getAppContext()
   if (context != null) {
      const manager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
      const currentLevel: number = manager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
      return '' + currentLevel + '%'
   }
   return '0%'
}
/**
 * 显示来电通知(锁屏/后台可弹出)
 * 利用高优先级通知 + fullScreenIntent 实现锁屏/后台来电提醒
 * @param callerName 来电者名称
 */
export function showIncomingCallNotification(callerName: string): void {
   const context = UTSAndroid.getAppContext()
   if (context == null) return
   try {
      const context = UTSAndroid.getAppContext();
      if (context == null) return;
      const wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager;
      wm.removeView(dialogView);
      // 1. 创建来电通知渠道(IMPORTANCE_HIGH → Heads-up 弹出)
      if (Build.VERSION.SDK_INT >= 26) {
         const channel = new NotificationChannel(
            CALL_CHANNEL_ID,
            '来电通知',
            NotificationManager.IMPORTANCE_HIGH
         )
         channel.setDescription('语音来电通知')
         channel.enableVibration(true)
         channel.enableLights(true)
         channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC)
         channel.setBypassDnd(true)
         const nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
         nm.createNotificationChannel(channel)
      }
      // 2. 构建点击通知后打开应用的 Intent
      const pm = context.getPackageManager()
      const launchIntent = pm.getLaunchIntentForPackage(context.getPackageName())
      if (launchIntent != null) {
         launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
         launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
      }
      let pendingIntentFlags = PendingIntent.FLAG_UPDATE_CURRENT
      if (Build.VERSION.SDK_INT >= 31) {
         pendingIntentFlags = pendingIntentFlags | PendingIntent.FLAG_IMMUTABLE
      }
      const contentIntent = PendingIntent.getActivity(context, 0, launchIntent, pendingIntentFlags)
      // fullScreenIntent 用于锁屏时全屏展示
      const fullScreenIntent = PendingIntent.getActivity(context, 1, launchIntent, pendingIntentFlags)
      // 3. 构建通知
      const appInfo = context.getApplicationInfo()
      const appIcon = appInfo.icon
      let builder: Notification.Builder
      if (Build.VERSION.SDK_INT >= 26) {
         builder = new Notification.Builder(context, CALL_CHANNEL_ID)
      } else {
         builder = new Notification.Builder(context)
      }
      builder
         .setSmallIcon(appIcon)
         .setContentTitle('语音来电')
         .setContentText(callerName + ' 正在呼叫您')
         .setContentIntent(contentIntent)
         .setFullScreenIntent(fullScreenIntent, true)  // 🔑 锁屏全屏弹出
         .setOngoing(true)
         .setAutoCancel(false)
         .setPriority(Notification.PRIORITY_MAX)
         .setVisibility(Notification.VISIBILITY_PUBLIC) // 锁屏显示完整内容
      if (Build.VERSION.SDK_INT >= 21) {
         builder.setCategory(Notification.CATEGORY_CALL) // 标记为来电类型
      }
      const notification = builder.build()
      // 设置通知标志:保持常亮、不可清除
      notification.flags = notification.flags | Notification.FLAG_INSISTENT | Notification.FLAG_NO_CLEAR
      // 4. 发送通知
      const notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
      notificationManager.notify(CALL_NOTIFICATION_ID, notification)
      // 5. 如果在锁屏状态,尝试亮屏
      wakeUpScreen(context)
      console.log('showIncomingCallNotification: 来电通知已发送,来电者:', callerName)
   } catch (e) {
      console.error(e);
   } finally {
      dialogView = null;
      console.error('showIncomingCallNotification: 发送来电通知失败', e)
   }
}
/**
 * 取消来电通知
 * 在接听或拒接后调用
 */
export function cancelIncomingCallNotification(): void {
   const context = UTSAndroid.getAppContext()
   if (context == null) return
   try {
      const notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
      notificationManager.cancel(CALL_NOTIFICATION_ID)
      console.log('cancelIncomingCallNotification: 来电通知已取消')
   } catch (e) {
      console.error('cancelIncomingCallNotification: 取消来电通知失败', e)
   }
}
/**
 * 唤醒屏幕(锁屏时亮屏)
 */
function wakeUpScreen(context: Context): void {
   try {
      const powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager
      if (!powerManager.isInteractive()) {
         // 屏幕关闭,唤醒屏幕
         const screenLock = powerManager.newWakeLock(
            PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
            'IncomingCall::WakeUp'
         )
         screenLock.acquire(10000) // 保持亮屏 10 秒
      }
   } catch (e) {
      console.error('wakeUpScreen: 唤醒屏幕失败', e)
   }
}