新增服务组件和工具类
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
package com.miraclegarden.smsmessage.service;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
/**
|
||||
* 开机后重启监听服务。
|
||||
*/
|
||||
public class BootReceiver extends BroadcastReceiver {
|
||||
private static final long BOOT_DELAY_MS = 5000;
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
|
||||
new Handler(Looper.getMainLooper()).postDelayed(() -> {
|
||||
NotificationService.requestStartMonitoring(context);
|
||||
}, BOOT_DELAY_MS);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
package com.miraclegarden.smsmessage.service;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.os.Bundle;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.text.TextUtils;
|
||||
|
||||
/**
|
||||
* @Author wchino
|
||||
* 创建时间 2026/03/30
|
||||
* 用途:通知内容多层提取工具,兼容不同厂商字段差异
|
||||
*/
|
||||
public class NotificationExtractor {
|
||||
|
||||
private NotificationExtractor() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author wchino
|
||||
* 创建时间 2026/03/30
|
||||
* 用途:提取通知标题、内容和提取时间戳
|
||||
*/
|
||||
public static Result extract(StatusBarNotification sbn) {
|
||||
long timestamp = System.currentTimeMillis();
|
||||
if (sbn == null || sbn.getNotification() == null) {
|
||||
return new Result("", "", timestamp);
|
||||
}
|
||||
|
||||
Notification notification = sbn.getNotification();
|
||||
Bundle extras = notification.extras;
|
||||
|
||||
String title = "";
|
||||
String content = "";
|
||||
|
||||
if (extras != null) {
|
||||
title = pickFirstNonEmpty(
|
||||
extras.getCharSequence(Notification.EXTRA_TITLE),
|
||||
extras.getCharSequence(Notification.EXTRA_TITLE_BIG)
|
||||
);
|
||||
|
||||
content = pickFirstNonEmpty(
|
||||
extras.getCharSequence(Notification.EXTRA_TEXT),
|
||||
extras.getCharSequence(Notification.EXTRA_BIG_TEXT),
|
||||
extras.getCharSequence(Notification.EXTRA_INFO_TEXT),
|
||||
extras.getCharSequence(Notification.EXTRA_SUB_TEXT)
|
||||
);
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(title)) {
|
||||
title = firstSegment(notification.tickerText);
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(content)) {
|
||||
content = normalized(notification.tickerText);
|
||||
}
|
||||
|
||||
if (title == null) {
|
||||
title = "";
|
||||
}
|
||||
if (content == null) {
|
||||
content = "";
|
||||
}
|
||||
|
||||
return new Result(title, content, timestamp);
|
||||
}
|
||||
|
||||
private static String pickFirstNonEmpty(CharSequence... values) {
|
||||
if (values == null || values.length == 0) {
|
||||
return "";
|
||||
}
|
||||
for (CharSequence value : values) {
|
||||
String normalized = normalized(value);
|
||||
if (!TextUtils.isEmpty(normalized)) {
|
||||
return normalized;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private static String normalized(CharSequence value) {
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
String result = value.toString().trim();
|
||||
if (TextUtils.isEmpty(result)) {
|
||||
return "";
|
||||
}
|
||||
if ("null".equalsIgnoreCase(result)) {
|
||||
return "";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static String firstSegment(CharSequence tickerText) {
|
||||
String ticker = normalized(tickerText);
|
||||
if (TextUtils.isEmpty(ticker)) {
|
||||
return "";
|
||||
}
|
||||
int spaceIndex = ticker.indexOf(' ');
|
||||
if (spaceIndex > 0) {
|
||||
return ticker.substring(0, spaceIndex).trim();
|
||||
}
|
||||
return ticker;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author wchino
|
||||
* 创建时间 2026/03/30
|
||||
* 用途:通知提取结果对象
|
||||
*/
|
||||
public static class Result {
|
||||
public String title;
|
||||
public String content;
|
||||
public long timestamp;
|
||||
|
||||
public Result(String title, String content, long timestamp) {
|
||||
this.title = title == null ? "" : title;
|
||||
this.content = content == null ? "" : content;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.miraclegarden.smsmessage.service;
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.work.Worker;
|
||||
import androidx.work.WorkerParameters;
|
||||
|
||||
public class NotificationHealthCheckWorker extends Worker {
|
||||
|
||||
public NotificationHealthCheckWorker(@NonNull Context context, @NonNull WorkerParameters params) {
|
||||
super(context, params);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Result doWork() {
|
||||
if (!isNotificationListenerEnabled()) {
|
||||
NotificationService.toggleNotificationListenerService(getApplicationContext());
|
||||
}
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
private boolean isNotificationListenerEnabled() {
|
||||
String flat = Settings.Secure.getString(
|
||||
getApplicationContext().getContentResolver(),
|
||||
"enabled_notification_listeners");
|
||||
if (TextUtils.isEmpty(flat)) {
|
||||
return false;
|
||||
}
|
||||
return flat.contains(getApplicationContext().getPackageName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,272 @@
|
||||
package com.miraclegarden.smsmessage.service;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 上传失败重试管理器(内存队列 + SharedPreferences 持久化)。
|
||||
* <p>
|
||||
* 主要职责:
|
||||
* 1. 入队失败上传任务并立即尝试上传;
|
||||
* 2. 上传失败后按延迟策略重试;
|
||||
* 3. 进程重启后从本地恢复重试队列;
|
||||
* 4. 统计成功上传总数,供前台通知展示。
|
||||
*/
|
||||
public class RetryManager {
|
||||
private static final String TAG = "RetryManager";
|
||||
|
||||
private static final String SP_NAME = "server";
|
||||
private static final String KEY_RETRY_QUEUE = "retry_queue";
|
||||
private static final String KEY_UPLOADED_COUNT = "uploaded_count";
|
||||
private static final String KEY_TOTAL_COUNT = "total_count";
|
||||
private static final String KEY_FAILED_COUNT = "failed_count";
|
||||
|
||||
private static final int MAX_QUEUE_SIZE = 100;
|
||||
private static final long[] RETRY_DELAYS = new long[]{2000L, 5000L, 15000L};
|
||||
|
||||
private final SharedPreferences sharedPreferences;
|
||||
private final Handler handler;
|
||||
private final List<QueueItem> retryQueue = new ArrayList<>();
|
||||
|
||||
private UploadCallback uploadCallback;
|
||||
private int uploadedCount;
|
||||
private int totalCount;
|
||||
private int failedCount;
|
||||
|
||||
/**
|
||||
* 上传抽象回调。
|
||||
*/
|
||||
public interface UploadCallback {
|
||||
void onUpload(String jsonPayload, UploadResultListener listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传结果监听。
|
||||
*/
|
||||
public interface UploadResultListener {
|
||||
void onSuccess();
|
||||
|
||||
void onFailure(String error);
|
||||
}
|
||||
|
||||
/**
|
||||
* 重试队列元素。
|
||||
*/
|
||||
private static class QueueItem {
|
||||
String jsonPayload;
|
||||
int retryCount; // starts at 0, max 2 (3 attempts total: initial + 2 retries)
|
||||
long nextRetryTime;
|
||||
}
|
||||
|
||||
public RetryManager(Context context) {
|
||||
Context appContext = context.getApplicationContext();
|
||||
this.sharedPreferences = appContext.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
|
||||
this.handler = new Handler(Looper.getMainLooper());
|
||||
this.uploadedCount = sharedPreferences.getInt(KEY_UPLOADED_COUNT, 0);
|
||||
this.totalCount = sharedPreferences.getInt(KEY_TOTAL_COUNT, 0);
|
||||
this.failedCount = sharedPreferences.getInt(KEY_FAILED_COUNT, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置上传实现。
|
||||
*/
|
||||
public void setUploadCallback(UploadCallback callback) {
|
||||
this.uploadCallback = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加任务到队列并立即尝试上传。
|
||||
*/
|
||||
public void enqueue(String jsonPayload) {
|
||||
if (jsonPayload == null || jsonPayload.trim().isEmpty()) {
|
||||
Log.w(TAG, "enqueue payload 为空,忽略");
|
||||
return;
|
||||
}
|
||||
|
||||
incrementTotalCount();
|
||||
|
||||
QueueItem item = new QueueItem();
|
||||
item.jsonPayload = jsonPayload;
|
||||
item.retryCount = 0;
|
||||
item.nextRetryTime = SystemClock.elapsedRealtime();
|
||||
|
||||
synchronized (retryQueue) {
|
||||
if (retryQueue.size() >= MAX_QUEUE_SIZE) {
|
||||
QueueItem removed = retryQueue.remove(0);
|
||||
Log.w(TAG, "重试队列已满,丢弃最旧任务: " + (removed == null ? "null" : removed.jsonPayload));
|
||||
}
|
||||
retryQueue.add(item);
|
||||
persistQueue();
|
||||
}
|
||||
|
||||
attemptUpload(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从持久化恢复重试队列并重新触发上传。
|
||||
*/
|
||||
public void restoreFromPersistence() {
|
||||
String queueJson = sharedPreferences.getString(KEY_RETRY_QUEUE, "");
|
||||
if (queueJson == null || queueJson.trim().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<QueueItem> restoredItems = new ArrayList<>();
|
||||
try {
|
||||
JSONArray jsonArray = new JSONArray(queueJson);
|
||||
for (int i = 0; i < jsonArray.length(); i++) {
|
||||
JSONObject object = jsonArray.optJSONObject(i);
|
||||
if (object == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QueueItem item = new QueueItem();
|
||||
item.jsonPayload = object.optString("jsonPayload", "");
|
||||
item.retryCount = object.optInt("retryCount", 0);
|
||||
item.nextRetryTime = object.optLong("nextRetryTime", SystemClock.elapsedRealtime());
|
||||
|
||||
if (item.jsonPayload == null || item.jsonPayload.trim().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
restoredItems.add(item);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
Log.e(TAG, "恢复重试队列失败", e);
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (retryQueue) {
|
||||
retryQueue.clear();
|
||||
retryQueue.addAll(restoredItems);
|
||||
}
|
||||
|
||||
for (QueueItem item : new ArrayList<>(restoredItems)) {
|
||||
long delay = item.nextRetryTime - SystemClock.elapsedRealtime();
|
||||
if (delay > 0) {
|
||||
handler.postDelayed(() -> attemptUpload(item), delay);
|
||||
} else {
|
||||
attemptUpload(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取累计成功上传数量。
|
||||
*/
|
||||
public int getUploadedCount() {
|
||||
return uploadedCount;
|
||||
}
|
||||
|
||||
public int getTotalCount() {
|
||||
return totalCount;
|
||||
}
|
||||
|
||||
public int getFailedCount() {
|
||||
return failedCount;
|
||||
}
|
||||
|
||||
private void incrementTotalCount() {
|
||||
totalCount++;
|
||||
sharedPreferences.edit()
|
||||
.putInt(KEY_TOTAL_COUNT, totalCount)
|
||||
.apply();
|
||||
}
|
||||
|
||||
private void incrementFailedCount() {
|
||||
failedCount++;
|
||||
sharedPreferences.edit()
|
||||
.putInt(KEY_FAILED_COUNT, failedCount)
|
||||
.apply();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理回调,通常在 Service 销毁时调用。
|
||||
*/
|
||||
public void destroy() {
|
||||
handler.removeCallbacksAndMessages(null);
|
||||
}
|
||||
|
||||
private void attemptUpload(final QueueItem item) {
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (uploadCallback == null) {
|
||||
Log.w(TAG, "uploadCallback 未设置,无法上传");
|
||||
return;
|
||||
}
|
||||
|
||||
uploadCallback.onUpload(item.jsonPayload, new UploadResultListener() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
synchronized (retryQueue) {
|
||||
retryQueue.remove(item);
|
||||
persistQueue();
|
||||
}
|
||||
uploadedCount++;
|
||||
sharedPreferences.edit()
|
||||
.putInt(KEY_UPLOADED_COUNT, uploadedCount)
|
||||
.apply();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(String error) {
|
||||
synchronized (retryQueue) {
|
||||
if (!retryQueue.contains(item)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.retryCount < 3) {
|
||||
long delay = RETRY_DELAYS[Math.min(item.retryCount, RETRY_DELAYS.length - 1)];
|
||||
item.retryCount++;
|
||||
item.nextRetryTime = SystemClock.elapsedRealtime() + delay;
|
||||
handler.postDelayed(() -> attemptUpload(item), delay);
|
||||
persistQueue();
|
||||
Log.w(TAG, "上传失败,准备重试。retryCount=" + item.retryCount + ", error=" + error);
|
||||
} else {
|
||||
retryQueue.remove(item);
|
||||
persistQueue();
|
||||
incrementFailedCount();
|
||||
Log.e(TAG, "上传失败达到上限,丢弃任务: " + error);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void persistQueue() {
|
||||
JSONArray jsonArray = new JSONArray();
|
||||
synchronized (retryQueue) {
|
||||
Iterator<QueueItem> iterator = retryQueue.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
QueueItem item = iterator.next();
|
||||
JSONObject object = new JSONObject();
|
||||
try {
|
||||
object.put("jsonPayload", item.jsonPayload);
|
||||
object.put("retryCount", item.retryCount);
|
||||
object.put("nextRetryTime", item.nextRetryTime);
|
||||
jsonArray.put(object);
|
||||
} catch (JSONException e) {
|
||||
Log.e(TAG, "序列化重试项失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sharedPreferences.edit()
|
||||
.putString(KEY_RETRY_QUEUE, jsonArray.toString())
|
||||
.apply();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
package com.miraclegarden.smsmessage.util;
|
||||
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.PowerManager;
|
||||
import android.provider.Settings;
|
||||
|
||||
public class OEMBackgroundHelper {
|
||||
|
||||
private static final String MIUI_SECURITY = "com.miui.securitycenter";
|
||||
private static final String MIUI_AUTOSTART = "com.miui.permcenter.autostart.AutoStartManagementActivity";
|
||||
|
||||
private static final String COLOROS_SAFECENTER = "com.coloros.safecenter";
|
||||
private static final String COLOROS_STARTUP = "com.coloros.safecenter.permission.startup.StartupAppListActivity";
|
||||
|
||||
private static final String OPPO_SAFE = "com.oppo.safe";
|
||||
private static final String OPPO_STARTUP = "com.oppo.safe.permission.startup.StartupAppListActivity";
|
||||
|
||||
private static final String VIVO_PERMISSION = "com.vivo.permissionmanager";
|
||||
private static final String VIVO_BGSTARTUP = "com.vivo.permissionmanager.activity.BgStartUpManagerActivity";
|
||||
|
||||
private static final String IQOO_SECURE = "com.iqoo.secure";
|
||||
private static final String IQOO_BGSTARTUP = "com.iqoo.secure.ui.phoneoptimize.BgStartUpManager";
|
||||
|
||||
private static final String HUAWEI_SYSTEM_MANAGER = "com.huawei.systemmanager";
|
||||
private static final String HUAWEI_STARTUP_CTRL = "com.huawei.systemmanager.startupmgr.ui.StartupNormalAppListActivity";
|
||||
private static final String HUAWEI_POWER_MANAGER = "com.huawei.systemmanager.power.ui.HwPowerManagerActivity";
|
||||
|
||||
public static void openAutoStartSettings(Context context) {
|
||||
String manufacturer = Build.MANUFACTURER.toLowerCase();
|
||||
|
||||
Intent intent = new Intent();
|
||||
boolean success = false;
|
||||
|
||||
try {
|
||||
if (manufacturer.contains("xiaomi") || manufacturer.contains("redmi")) {
|
||||
intent.setComponent(new ComponentName(MIUI_SECURITY, MIUI_AUTOSTART));
|
||||
success = true;
|
||||
} else if (manufacturer.contains("oppo")) {
|
||||
if (tryStartActivity(context, intent, COLOROS_SAFECENTER, COLOROS_STARTUP)) return;
|
||||
if (tryStartActivity(context, intent, OPPO_SAFE, OPPO_STARTUP)) return;
|
||||
} else if (manufacturer.contains("realme")) {
|
||||
if (tryStartActivity(context, intent, COLOROS_SAFECENTER, COLOROS_STARTUP)) return;
|
||||
} else if (manufacturer.contains("vivo")) {
|
||||
if (tryStartActivity(context, intent, VIVO_PERMISSION, VIVO_BGSTARTUP)) return;
|
||||
if (tryStartActivity(context, intent, IQOO_SECURE, IQOO_BGSTARTUP)) return;
|
||||
} else if (manufacturer.contains("huawei") || manufacturer.contains("honor")) {
|
||||
if (tryStartActivity(context, intent, HUAWEI_SYSTEM_MANAGER, HUAWEI_STARTUP_CTRL)) return;
|
||||
if (tryStartActivity(context, intent, HUAWEI_SYSTEM_MANAGER, HUAWEI_POWER_MANAGER)) return;
|
||||
} else if (manufacturer.contains("oneplus")) {
|
||||
openBatteryOptimizationSettings(context);
|
||||
return;
|
||||
} else if (manufacturer.contains("samsung")) {
|
||||
openAppBatterySettings(context);
|
||||
return;
|
||||
}
|
||||
|
||||
if (success) {
|
||||
context.startActivity(intent);
|
||||
} else {
|
||||
openBatteryOptimizationSettings(context);
|
||||
}
|
||||
} catch (ActivityNotFoundException e) {
|
||||
openBatteryOptimizationSettings(context);
|
||||
}
|
||||
}
|
||||
|
||||
public static void openBatteryOptimizationSettings(Context context) {
|
||||
try {
|
||||
Intent intent = new Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
|
||||
context.startActivity(intent);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Intent intent = new Intent(Settings.ACTION_SETTINGS);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
}
|
||||
|
||||
public static void requestBatteryOptimizationExemption(Context context) {
|
||||
if (!isIgnoringBatteryOptimizations(context)) {
|
||||
try {
|
||||
Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
|
||||
intent.setData(Uri.parse("package:" + context.getPackageName()));
|
||||
context.startActivity(intent);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
openBatteryOptimizationSettings(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isIgnoringBatteryOptimizations(Context context) {
|
||||
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
|
||||
return pm.isIgnoringBatteryOptimizations(context.getPackageName());
|
||||
}
|
||||
|
||||
public static String getManufacturer() {
|
||||
return Build.MANUFACTURER;
|
||||
}
|
||||
|
||||
public static boolean needsAutoStartPermission() {
|
||||
String manufacturer = Build.MANUFACTURER.toLowerCase();
|
||||
return manufacturer.contains("xiaomi") || manufacturer.contains("redmi")
|
||||
|| manufacturer.contains("oppo") || manufacturer.contains("realme")
|
||||
|| manufacturer.contains("vivo") || manufacturer.contains("huawei")
|
||||
|| manufacturer.contains("honor") || manufacturer.contains("oneplus");
|
||||
}
|
||||
|
||||
public static String getAutoStartPermissionName() {
|
||||
String manufacturer = Build.MANUFACTURER.toLowerCase();
|
||||
if (manufacturer.contains("xiaomi") || manufacturer.contains("redmi")) {
|
||||
return "自启动";
|
||||
} else if (manufacturer.contains("oppo") || manufacturer.contains("realme")) {
|
||||
return "自动启动";
|
||||
} else if (manufacturer.contains("vivo")) {
|
||||
return "后台启动";
|
||||
} else if (manufacturer.contains("huawei") || manufacturer.contains("honor")) {
|
||||
return "自动启动管理";
|
||||
} else if (manufacturer.contains("oneplus")) {
|
||||
return "电池优化";
|
||||
}
|
||||
return "电池/自启动";
|
||||
}
|
||||
|
||||
private static boolean tryStartActivity(Context context, Intent intent, String pkg, String cls) {
|
||||
try {
|
||||
intent.setComponent(new ComponentName(pkg, cls));
|
||||
context.startActivity(intent);
|
||||
return true;
|
||||
} catch (ActivityNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void openAppBatterySettings(Context context) {
|
||||
try {
|
||||
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
|
||||
intent.setData(Uri.parse("package:" + context.getPackageName()));
|
||||
context.startActivity(intent);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Intent intent = new Intent(Settings.ACTION_SETTINGS);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user