吉安感知网项目-前端
chenyao
2 days ago 4c390d209b45d516fbe2f7552d26048687c83972
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
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'
 
// 来电通知相关常量
const CALL_CHANNEL_ID = 'incoming_call_channel'
const CALL_NOTIFICATION_ID: Int = 2001
 
// 拉起应用
export function openDialog(): void {
    const context = UTSAndroid.getAppContext()
    if (context == null) return
    try {
        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)
    }
}
 
// 跳到允许悬浮窗权限页面
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 {
        // 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('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)
    }
}