Compare commits
16 Commits
powerbell-
...
powerbell-
| Author | SHA1 | Date | |
|---|---|---|---|
| 08a33365b3 | |||
| 7cffe5c0a5 | |||
| 5a0c429131 | |||
| cff26b3d11 | |||
| e59034e48d | |||
| 3d3301064c | |||
| 2d12397f5e | |||
| f09bb17cbc | |||
| 28d8a5679f | |||
| b4d9bdf3b3 | |||
| 111cf01f9a | |||
| e51d46186a | |||
| 8fc6855066 | |||
| 4ceaf1e46a | |||
| e669bbb04b | |||
| 6bf3ebe2fd |
@@ -29,11 +29,11 @@ android {
|
|||||||
applicationId "cc.winboll.studio.powerbell"
|
applicationId "cc.winboll.studio.powerbell"
|
||||||
minSdkVersion 23
|
minSdkVersion 23
|
||||||
targetSdkVersion 30
|
targetSdkVersion 30
|
||||||
versionCode 6
|
versionCode 7
|
||||||
// versionName 更新后需要手动设置
|
// versionName 更新后需要手动设置
|
||||||
// .winboll/winbollBuildProps.properties 文件的 stageCount=0
|
// .winboll/winbollBuildProps.properties 文件的 stageCount=0
|
||||||
// Gradle编译环境下合起来的 versionName 就是 "${versionName}.0"
|
// Gradle编译环境下合起来的 versionName 就是 "${versionName}.0"
|
||||||
versionName "15.12"
|
versionName "15.14"
|
||||||
if(true) {
|
if(true) {
|
||||||
versionName = genVersionName("${versionName}")
|
versionName = genVersionName("${versionName}")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
#Created by .winboll/winboll_app_build.gradle
|
#Created by .winboll/winboll_app_build.gradle
|
||||||
#Thu Dec 11 20:54:28 HKT 2025
|
#Sun Dec 14 04:55:45 HKT 2025
|
||||||
stageCount=16
|
stageCount=3
|
||||||
libraryProject=
|
libraryProject=
|
||||||
baseVersion=15.12
|
baseVersion=15.14
|
||||||
publishVersion=15.12.15
|
publishVersion=15.14.2
|
||||||
buildCount=0
|
buildCount=0
|
||||||
baseBetaVersion=15.12.16
|
baseBetaVersion=15.14.3
|
||||||
|
|||||||
@@ -4,30 +4,12 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
package="cc.winboll.studio.powerbell">
|
package="cc.winboll.studio.powerbell">
|
||||||
|
|
||||||
<!-- 只能在前台获取精确的位置信息 -->
|
|
||||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
|
||||||
|
|
||||||
<!-- 只有在前台运行时才能获取大致位置信息 -->
|
|
||||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
|
|
||||||
|
|
||||||
<!-- 拍摄照片和视频 -->
|
|
||||||
<uses-permission android:name="android.permission.CAMERA"/>
|
|
||||||
|
|
||||||
<!-- 运行前台服务 -->
|
<!-- 运行前台服务 -->
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||||
|
|
||||||
<!-- 读取您共享存储空间中的内容 -->
|
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
|
||||||
|
|
||||||
<!-- 修改或删除您共享存储空间中的内容 -->
|
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
|
||||||
|
|
||||||
<!-- 开机启动 -->
|
<!-- 开机启动 -->
|
||||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||||
|
|
||||||
<!-- MANAGE_EXTERNAL_STORAGE -->
|
|
||||||
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
|
|
||||||
|
|
||||||
<!-- 显示通知 -->
|
<!-- 显示通知 -->
|
||||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||||
|
|
||||||
@@ -37,9 +19,6 @@
|
|||||||
<!-- BATTERY_STATS -->
|
<!-- BATTERY_STATS -->
|
||||||
<uses-permission android:name="android.permission.BATTERY_STATS"/>
|
<uses-permission android:name="android.permission.BATTERY_STATS"/>
|
||||||
|
|
||||||
<!-- 计算应用存储空间 -->
|
|
||||||
<uses-permission android:name="android.permission.GET_PACKAGE_SIZE"/>
|
|
||||||
|
|
||||||
<uses-feature android:name="android.hardware.camera"/>
|
<uses-feature android:name="android.hardware.camera"/>
|
||||||
|
|
||||||
<uses-feature android:name="android.hardware.camera.autofocus"/>
|
<uses-feature android:name="android.hardware.camera.autofocus"/>
|
||||||
@@ -143,14 +122,14 @@
|
|||||||
</activity-alias>
|
</activity-alias>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name="cc.winboll.studio.powerbell.activities.ClearRecordActivity"
|
android:name=".activities.ClearRecordActivity"
|
||||||
android:parentActivityName="cc.winboll.studio.powerbell.MainActivity"
|
android:parentActivityName="cc.winboll.studio.powerbell.MainActivity"
|
||||||
android:launchMode="singleTask">
|
android:launchMode="singleTask">
|
||||||
|
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name="cc.winboll.studio.powerbell.activities.BackgroundSettingsActivity"
|
android:name=".activities.BackgroundSettingsActivity"
|
||||||
android:parentActivityName="cc.winboll.studio.powerbell.MainActivity"
|
android:parentActivityName="cc.winboll.studio.powerbell.MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:launchMode="singleTask">
|
android:launchMode="singleTask">
|
||||||
@@ -190,14 +169,14 @@
|
|||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name="cc.winboll.studio.powerbell.services.ControlCenterService"
|
android:name=".services.ControlCenterService"
|
||||||
android:priority="1000"
|
android:priority="1000"
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:process=".controlcenterservice"/>
|
android:process=".controlcenterservice"/>
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name="cc.winboll.studio.powerbell.services.AssistantService"
|
android:name=".services.AssistantService"
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:process=".assistantservice"/>
|
android:process=".assistantservice"/>
|
||||||
@@ -206,13 +185,13 @@
|
|||||||
android:name="android.max_aspect"
|
android:name="android.max_aspect"
|
||||||
android:value="4.0"/>
|
android:value="4.0"/>
|
||||||
|
|
||||||
<activity android:name="cc.winboll.studio.powerbell.activities.BatteryReporterActivity"/>
|
<activity android:name=".activities.BatteryReporterActivity"/>
|
||||||
|
|
||||||
<activity android:name="cc.winboll.studio.powerbell.activities.PixelPickerActivity"/>
|
<activity android:name=".activities.PixelPickerActivity"/>
|
||||||
|
|
||||||
<activity android:name="cc.winboll.studio.powerbell.activities.BatteryReportActivity"/>
|
<activity android:name=".activities.BatteryReportActivity"/>
|
||||||
|
|
||||||
<activity android:name="cc.winboll.studio.powerbell.unittest.MainUnitTestActivity"/>
|
<activity android:name=".unittest.MainUnitTestActivity"/>
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:name="androidx.core.content.FileProvider"
|
android:name="androidx.core.content.FileProvider"
|
||||||
@@ -226,17 +205,17 @@
|
|||||||
|
|
||||||
</provider>
|
</provider>
|
||||||
|
|
||||||
<activity android:name="cc.winboll.studio.powerbell.activities.ShortcutActionActivity"/>
|
<activity android:name=".activities.ShortcutActionActivity"/>
|
||||||
|
|
||||||
<activity android:name="cc.winboll.studio.powerbell.activities.SettingsActivity"/>
|
<activity android:name=".activities.SettingsActivity"/>
|
||||||
|
|
||||||
<!-- 1. 注册 UCropActivity(关键:解决崩溃) -->
|
<activity
|
||||||
<activity
|
android:name="com.yalantis.ucrop.UCropActivity"
|
||||||
android:name="com.yalantis.ucrop.UCropActivity"
|
android:theme="@style/Theme.AppCompat.Light.NoActionBar"
|
||||||
android:theme="@style/Theme.AppCompat.Light.NoActionBar"
|
android:exported="true">
|
||||||
android:exported="true"> <!-- 必须添加:Android 12+ 要求显式声明 exported -->
|
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -8,13 +8,12 @@ import cc.winboll.studio.libaes.utils.WinBoLLActivityManager;
|
|||||||
import cc.winboll.studio.libappbase.GlobalApplication;
|
import cc.winboll.studio.libappbase.GlobalApplication;
|
||||||
import cc.winboll.studio.libappbase.LogUtils;
|
import cc.winboll.studio.libappbase.LogUtils;
|
||||||
import cc.winboll.studio.libappbase.ToastUtils;
|
import cc.winboll.studio.libappbase.ToastUtils;
|
||||||
import cc.winboll.studio.powerbell.model.BackgroundBean;
|
import cc.winboll.studio.powerbell.models.BackgroundBean;
|
||||||
import cc.winboll.studio.powerbell.receivers.GlobalApplicationReceiver;
|
import cc.winboll.studio.powerbell.receivers.GlobalApplicationReceiver;
|
||||||
import cc.winboll.studio.powerbell.utils.AppCacheUtils;
|
import cc.winboll.studio.powerbell.utils.AppCacheUtils;
|
||||||
import cc.winboll.studio.powerbell.utils.AppConfigUtils;
|
import cc.winboll.studio.powerbell.utils.AppConfigUtils;
|
||||||
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
|
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
|
||||||
import cc.winboll.studio.powerbell.utils.BitmapCacheUtils;
|
import cc.winboll.studio.powerbell.utils.BitmapCacheUtils;
|
||||||
import cc.winboll.studio.powerbell.utils.PermissionUtils;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
public class App extends GlobalApplication {
|
public class App extends GlobalApplication {
|
||||||
|
|||||||
@@ -25,19 +25,21 @@ import android.widget.Switch;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import androidx.appcompat.widget.Toolbar;
|
import androidx.appcompat.widget.Toolbar;
|
||||||
import cc.winboll.studio.libaes.activitys.AboutActivity;
|
import cc.winboll.studio.libaes.activitys.AboutActivity;
|
||||||
|
import cc.winboll.studio.libaes.dialogs.YesNoAlertDialog;
|
||||||
import cc.winboll.studio.libaes.models.APPInfo;
|
import cc.winboll.studio.libaes.models.APPInfo;
|
||||||
import cc.winboll.studio.libaes.utils.AESThemeUtil;
|
import cc.winboll.studio.libaes.utils.AESThemeUtil;
|
||||||
import cc.winboll.studio.libaes.utils.DevelopUtils;
|
import cc.winboll.studio.libaes.utils.DevelopUtils;
|
||||||
import cc.winboll.studio.libaes.utils.WinBoLLActivityManager;
|
import cc.winboll.studio.libaes.utils.WinBoLLActivityManager;
|
||||||
import cc.winboll.studio.libaes.views.ADsBannerView;
|
import cc.winboll.studio.libaes.views.ADsBannerView;
|
||||||
import cc.winboll.studio.libappbase.LogUtils;
|
import cc.winboll.studio.libappbase.LogUtils;
|
||||||
|
import cc.winboll.studio.libappbase.ToastUtils;
|
||||||
import cc.winboll.studio.powerbell.activities.BackgroundSettingsActivity;
|
import cc.winboll.studio.powerbell.activities.BackgroundSettingsActivity;
|
||||||
import cc.winboll.studio.powerbell.activities.BatteryReportActivity;
|
import cc.winboll.studio.powerbell.activities.BatteryReportActivity;
|
||||||
import cc.winboll.studio.powerbell.activities.ClearRecordActivity;
|
import cc.winboll.studio.powerbell.activities.ClearRecordActivity;
|
||||||
import cc.winboll.studio.powerbell.activities.SettingsActivity;
|
import cc.winboll.studio.powerbell.activities.SettingsActivity;
|
||||||
import cc.winboll.studio.powerbell.activities.WinBoLLActivity;
|
import cc.winboll.studio.powerbell.activities.WinBoLLActivity;
|
||||||
import cc.winboll.studio.powerbell.fragments.MainViewFragment;
|
import cc.winboll.studio.powerbell.fragments.MainViewFragment;
|
||||||
import cc.winboll.studio.powerbell.model.BackgroundBean;
|
import cc.winboll.studio.powerbell.models.BackgroundBean;
|
||||||
import cc.winboll.studio.powerbell.services.ControlCenterService;
|
import cc.winboll.studio.powerbell.services.ControlCenterService;
|
||||||
import cc.winboll.studio.powerbell.unittest.MainUnitTestActivity;
|
import cc.winboll.studio.powerbell.unittest.MainUnitTestActivity;
|
||||||
import cc.winboll.studio.powerbell.utils.AppConfigUtils;
|
import cc.winboll.studio.powerbell.utils.AppConfigUtils;
|
||||||
@@ -68,6 +70,7 @@ public class MainActivity extends WinBoLLActivity {
|
|||||||
public static MainActivity _mMainActivity;
|
public static MainActivity _mMainActivity;
|
||||||
static MainViewFragment _mMainViewFragment;
|
static MainViewFragment _mMainViewFragment;
|
||||||
static Handler _mHandler;
|
static Handler _mHandler;
|
||||||
|
PermissionUtils permissionUtils = PermissionUtils.getInstance();
|
||||||
|
|
||||||
private App mApplication;
|
private App mApplication;
|
||||||
private AppConfigUtils mAppConfigUtils;
|
private AppConfigUtils mAppConfigUtils;
|
||||||
@@ -121,13 +124,26 @@ public class MainActivity extends WinBoLLActivity {
|
|||||||
initViewHolder();
|
initViewHolder();
|
||||||
initCriticalView();
|
initCriticalView();
|
||||||
loadNonCriticalViewDelayed();
|
loadNonCriticalViewDelayed();
|
||||||
|
|
||||||
// 权限申请
|
|
||||||
PermissionUtils.getInstance().checkAndRequestMediaImagesPermission(this, REQUEST_READ_MEDIA_IMAGES);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 移除 onSaveInstanceState 方法
|
@Override
|
||||||
// 移除 onRestoreInstanceState 方法
|
protected void onPostCreate(Bundle savedInstanceState) {
|
||||||
|
super.onPostCreate(savedInstanceState);
|
||||||
|
|
||||||
|
// 电池优化权限(通用所有机型)
|
||||||
|
if (!permissionUtils.checkIgnoreBatteryOptimizationPermission(this)) {
|
||||||
|
YesNoAlertDialog.show(this, getString(R.string.app_name) + "权限申请提示:", "本应用要正常使用,需要申请电池优化与自启动权限。是否进入权限设置步骤?", new YesNoAlertDialog.OnDialogResultListener(){
|
||||||
|
@Override
|
||||||
|
public void onNo() {
|
||||||
|
ToastUtils.show(getString(R.string.app_name) + "应用可能无法正常使用。");
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void onYes() {
|
||||||
|
permissionUtils.requestIgnoreBatteryOptimizationPermission(MainActivity.this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
@@ -189,7 +205,7 @@ public class MainActivity extends WinBoLLActivity {
|
|||||||
startActivity(new Intent(this, ClearRecordActivity.class));
|
startActivity(new Intent(this, ClearRecordActivity.class));
|
||||||
break;
|
break;
|
||||||
case R.id.action_changepicture:
|
case R.id.action_changepicture:
|
||||||
startActivity(new Intent(this, BackgroundSettingsActivity.class));
|
startActivityForResult(new Intent(this, BackgroundSettingsActivity.class), REQUEST_READ_MEDIA_IMAGES);
|
||||||
break;
|
break;
|
||||||
case R.id.action_unittestactivity:
|
case R.id.action_unittestactivity:
|
||||||
startActivity(new Intent(this, MainUnitTestActivity.class));
|
startActivity(new Intent(this, MainUnitTestActivity.class));
|
||||||
@@ -209,20 +225,20 @@ public class MainActivity extends WinBoLLActivity {
|
|||||||
@Override
|
@Override
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
|
||||||
|
if (requestCode == PermissionUtils.REQUEST_IGNORE_BATTERY_OPTIMIZATION) {
|
||||||
|
// 自启动权限(小米专属)
|
||||||
|
if (permissionUtils.checkAutoStartPermission(this)) {
|
||||||
|
// 小米机型,发起自启动权限申请
|
||||||
|
permissionUtils.requestAutoStartPermission(this);
|
||||||
|
}
|
||||||
|
} else if (requestCode == REQUEST_READ_MEDIA_IMAGES) {
|
||||||
if (_mHandler != null) {
|
if (_mHandler != null) {
|
||||||
_mHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND);
|
_mHandler.sendEmptyMessage(MSG_LOAD_BACKGROUND);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
|
||||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
|
||||||
if (requestCode == REQUEST_READ_MEDIA_IMAGES) {
|
|
||||||
PermissionUtils.getInstance().handleStoragePermissionResult(this, requestCode, permissions, grantResults);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBackPressed() {
|
public void onBackPressed() {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package cc.winboll.studio.powerbell.activities;
|
|||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Bitmap.CompressFormat;
|
import android.graphics.Bitmap.CompressFormat;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
@@ -15,6 +16,7 @@ import android.os.Looper;
|
|||||||
import android.provider.MediaStore;
|
import android.provider.MediaStore;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.appcompat.widget.Toolbar;
|
import androidx.appcompat.widget.Toolbar;
|
||||||
import androidx.core.content.FileProvider;
|
import androidx.core.content.FileProvider;
|
||||||
@@ -24,13 +26,12 @@ import cc.winboll.studio.powerbell.App;
|
|||||||
import cc.winboll.studio.powerbell.R;
|
import cc.winboll.studio.powerbell.R;
|
||||||
import cc.winboll.studio.powerbell.dialogs.BackgroundPicturePreviewDialog;
|
import cc.winboll.studio.powerbell.dialogs.BackgroundPicturePreviewDialog;
|
||||||
import cc.winboll.studio.powerbell.dialogs.YesNoAlertDialog;
|
import cc.winboll.studio.powerbell.dialogs.YesNoAlertDialog;
|
||||||
import cc.winboll.studio.powerbell.model.BackgroundBean;
|
import cc.winboll.studio.powerbell.models.BackgroundBean;
|
||||||
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
|
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
|
||||||
import cc.winboll.studio.powerbell.utils.BitmapCacheUtils;
|
import cc.winboll.studio.powerbell.utils.BitmapCacheUtils;
|
||||||
import cc.winboll.studio.powerbell.utils.FileUtils;
|
import cc.winboll.studio.powerbell.utils.FileUtils;
|
||||||
import cc.winboll.studio.powerbell.utils.ImageCropUtils;
|
import cc.winboll.studio.powerbell.utils.ImageCropUtils;
|
||||||
import cc.winboll.studio.powerbell.utils.PermissionUtils;
|
import cc.winboll.studio.powerbell.utils.UriUtils;
|
||||||
import cc.winboll.studio.powerbell.utils.UriUtil;
|
|
||||||
import cc.winboll.studio.powerbell.views.BackgroundView;
|
import cc.winboll.studio.powerbell.views.BackgroundView;
|
||||||
import java.io.BufferedOutputStream;
|
import java.io.BufferedOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -38,7 +39,7 @@ import java.io.FileOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
public class BackgroundSettingsActivity extends WinBoLLActivity implements BackgroundPicturePreviewDialog.IOnRecivedPictureListener {
|
public class BackgroundSettingsActivity extends WinBoLLActivity {
|
||||||
|
|
||||||
// ====================== 常量定义 ======================
|
// ====================== 常量定义 ======================
|
||||||
public static final String TAG = "BackgroundSettingsActivity";
|
public static final String TAG = "BackgroundSettingsActivity";
|
||||||
@@ -47,11 +48,10 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
|||||||
public static final int REQUEST_SELECT_PICTURE = 0;
|
public static final int REQUEST_SELECT_PICTURE = 0;
|
||||||
public static final int REQUEST_TAKE_PHOTO = 1;
|
public static final int REQUEST_TAKE_PHOTO = 1;
|
||||||
public static final int REQUEST_CROP_IMAGE = 2;
|
public static final int REQUEST_CROP_IMAGE = 2;
|
||||||
private static final int REQUEST_READ_MEDIA = 1001;
|
private static final int REQUEST_PIXELPICKER = 1001;
|
||||||
|
|
||||||
// ====================== 成员变量 ======================
|
// ====================== 成员变量 ======================
|
||||||
private BackgroundSourceUtils mBgSourceUtils;
|
private BackgroundSourceUtils mBgSourceUtils;
|
||||||
private PermissionUtils mPermissionUtils;
|
|
||||||
private BitmapCacheUtils mBitmapCache;
|
private BitmapCacheUtils mBitmapCache;
|
||||||
|
|
||||||
private Toolbar mToolbar;
|
private Toolbar mToolbar;
|
||||||
@@ -81,7 +81,6 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
|||||||
mBackgroundView = findViewById(R.id.background_view);
|
mBackgroundView = findViewById(R.id.background_view);
|
||||||
mBgSourceUtils = BackgroundSourceUtils.getInstance(this);
|
mBgSourceUtils = BackgroundSourceUtils.getInstance(this);
|
||||||
mBgSourceUtils.loadSettings();
|
mBgSourceUtils.loadSettings();
|
||||||
mPermissionUtils = PermissionUtils.getInstance();
|
|
||||||
mBitmapCache = BitmapCacheUtils.getInstance();
|
mBitmapCache = BitmapCacheUtils.getInstance();
|
||||||
|
|
||||||
// 初始化临时文件与目录
|
// 初始化临时文件与目录
|
||||||
@@ -91,11 +90,11 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
|||||||
}
|
}
|
||||||
mfTakePhoto = new File(tempDir, "TakePhoto.jpg");
|
mfTakePhoto = new File(tempDir, "TakePhoto.jpg");
|
||||||
|
|
||||||
File selectTempDir = new File(mBgSourceUtils.getBackgroundSourceDirPath(), "SelectTemp");
|
// File selectTempDir = new File(mBgSourceUtils.getBackgroundSourceDirPath(), "SelectTemp");
|
||||||
if (!selectTempDir.exists()) {
|
// if (!selectTempDir.exists()) {
|
||||||
selectTempDir.mkdirs();
|
// selectTempDir.mkdirs();
|
||||||
LogUtils.d(TAG, "【目录初始化】选图临时目录创建完成:" + selectTempDir.getAbsolutePath());
|
// LogUtils.d(TAG, "【目录初始化】选图临时目录创建完成:" + selectTempDir.getAbsolutePath());
|
||||||
}
|
// }
|
||||||
|
|
||||||
// 初始化界面与事件
|
// 初始化界面与事件
|
||||||
initToolbar();
|
initToolbar();
|
||||||
@@ -126,11 +125,6 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
|||||||
LogUtils.d(TAG, "【回调触发】requestCode:" + requestCode + ",resultCode:" + resultCode);
|
LogUtils.d(TAG, "【回调触发】requestCode:" + requestCode + ",resultCode:" + resultCode);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (requestCode == PermissionUtils.REQUEST_READ_MEDIA_IMAGES && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
|
||||||
handleStoragePermissionCallback();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resultCode != RESULT_OK) {
|
if (resultCode != RESULT_OK) {
|
||||||
handleOperationCancelOrFail();
|
handleOperationCancelOrFail();
|
||||||
return;
|
return;
|
||||||
@@ -145,6 +139,9 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
|||||||
break;
|
break;
|
||||||
case REQUEST_CROP_IMAGE:
|
case REQUEST_CROP_IMAGE:
|
||||||
handleCropImageResult(requestCode, resultCode, data);
|
handleCropImageResult(requestCode, resultCode, data);
|
||||||
|
break;
|
||||||
|
case REQUEST_PIXELPICKER:
|
||||||
|
handlePixelPickerResult(requestCode, resultCode, data);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LogUtils.d(TAG, "【回调忽略】未知requestCode");
|
LogUtils.d(TAG, "【回调忽略】未知requestCode");
|
||||||
@@ -156,39 +153,29 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
|
||||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
|
||||||
LogUtils.d(TAG, "【权限回调】转发处理 requestCode:" + requestCode);
|
|
||||||
mPermissionUtils.handleStoragePermissionResult(this, requestCode, permissions, grantResults);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void finish() {
|
public void finish() {
|
||||||
LogUtils.d(TAG, "【生命周期】finish 触发,isCommitSettings:" + isCommitSettings + ",isPreviewBackgroundChanged:" + isPreviewBackgroundChanged);
|
LogUtils.d(TAG, "【生命周期】finish 触发,isCommitSettings:" + isCommitSettings + ",isPreviewBackgroundChanged:" + isPreviewBackgroundChanged);
|
||||||
if (isCommitSettings) {
|
if (isCommitSettings) {
|
||||||
setResult(RESULT_OK);
|
|
||||||
super.finish();
|
super.finish();
|
||||||
} else {
|
} else {
|
||||||
if (isPreviewBackgroundChanged) {
|
if (isPreviewBackgroundChanged) {
|
||||||
YesNoAlertDialog.show(this, "背景更换问题", "是否确定背景图片设置?", new YesNoAlertDialog.OnDialogResultListener() {
|
YesNoAlertDialog.show(this, "背景更换问题", "是否确定背景图片设置?", new YesNoAlertDialog.OnDialogResultListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onYes() {
|
public void onYes() {
|
||||||
|
//ToastUtils.show("onYes");
|
||||||
mBgSourceUtils.commitPreviewSourceToCurrent();
|
mBgSourceUtils.commitPreviewSourceToCurrent();
|
||||||
isCommitSettings = true;
|
isCommitSettings = true;
|
||||||
setResult(RESULT_OK);
|
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNo() {
|
public void onNo() {
|
||||||
isCommitSettings = true;
|
isCommitSettings = true;
|
||||||
setResult(RESULT_CANCELED);
|
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
setResult(RESULT_OK);
|
|
||||||
isCommitSettings = true;
|
isCommitSettings = true;
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
@@ -238,15 +225,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
|||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
LogUtils.d(TAG, "【按钮点击】选择图片");
|
LogUtils.d(TAG, "【按钮点击】选择图片");
|
||||||
if (Build.VERSION.SDK_INT >= SDK_VERSION_TIRAMISU) {
|
launchImageSelector();
|
||||||
if (mPermissionUtils.checkAndRequestMediaImagesPermission(BackgroundSettingsActivity.this, REQUEST_READ_MEDIA)) {
|
|
||||||
launchImageSelector();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (mPermissionUtils.checkAndRequestStoragePermission(BackgroundSettingsActivity.this)) {
|
|
||||||
launchImageSelector();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -296,22 +275,17 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mPermissionUtils.checkAndRequestStoragePermission(BackgroundSettingsActivity.this)) {
|
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
|
||||||
LogUtils.d(TAG, "【拍照权限】已获取");
|
try {
|
||||||
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
|
Uri photoUri = getFileProviderUri(mfTakePhoto);
|
||||||
try {
|
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
|
||||||
Uri photoUri = getFileProviderUri(mfTakePhoto);
|
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
|
||||||
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
|
LogUtils.d(TAG, "【拍照启动】Uri:" + photoUri.toString());
|
||||||
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
|
} catch (Exception e) {
|
||||||
LogUtils.d(TAG, "【拍照启动】Uri:" + photoUri.toString());
|
String errMsg = "拍照启动异常:" + e.getMessage();
|
||||||
} catch (Exception e) {
|
ToastUtils.show(errMsg.substring(0, 20));
|
||||||
String errMsg = "拍照启动异常:" + e.getMessage();
|
LogUtils.e(TAG, "【拍照失败】" + e.getMessage());
|
||||||
ToastUtils.show(errMsg.substring(0, 20));
|
}
|
||||||
LogUtils.e(TAG, "【拍照失败】" + e.getMessage());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LogUtils.d(TAG, "【拍照权限】已申请");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -324,10 +298,11 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
|||||||
};
|
};
|
||||||
|
|
||||||
private View.OnClickListener onPixelPickerClickListener = new View.OnClickListener() {
|
private View.OnClickListener onPixelPickerClickListener = new View.OnClickListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
LogUtils.d(TAG, "【按钮点击】像素拾取");
|
LogUtils.d(TAG, "【按钮点击】像素拾取");
|
||||||
String targetImagePath = mBgSourceUtils.getCurrentBackgroundBean().getBackgroundFilePath();
|
String targetImagePath = mBgSourceUtils.getPreviewBackgroundBean().getBackgroundFilePath();
|
||||||
File targetFile = new File(targetImagePath);
|
File targetFile = new File(targetImagePath);
|
||||||
if (targetFile == null || !targetFile.exists() || targetFile.length() <= 0) {
|
if (targetFile == null || !targetFile.exists() || targetFile.length() <= 0) {
|
||||||
ToastUtils.show("无有效图片可拾取像素");
|
ToastUtils.show("无有效图片可拾取像素");
|
||||||
@@ -336,7 +311,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
|||||||
}
|
}
|
||||||
Intent intent = new Intent(getApplicationContext(), PixelPickerActivity.class);
|
Intent intent = new Intent(getApplicationContext(), PixelPickerActivity.class);
|
||||||
intent.putExtra("imagePath", targetImagePath);
|
intent.putExtra("imagePath", targetImagePath);
|
||||||
startActivity(intent);
|
startActivityForResult(intent, REQUEST_PIXELPICKER);
|
||||||
LogUtils.d(TAG, "【像素拾取启动】路径:" + targetImagePath);
|
LogUtils.d(TAG, "【像素拾取启动】路径:" + targetImagePath);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -345,11 +320,12 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
|||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
LogUtils.d(TAG, "【按钮点击】清空像素颜色");
|
LogUtils.d(TAG, "【按钮点击】清空像素颜色");
|
||||||
BackgroundBean bean = mBgSourceUtils.getCurrentBackgroundBean();
|
BackgroundBean bean = mBgSourceUtils.getPreviewBackgroundBean();
|
||||||
int oldColor = bean.getPixelColor();
|
int oldColor = bean.getPixelColor();
|
||||||
bean.setPixelColor(0);
|
bean.setPixelColor(0);
|
||||||
mBgSourceUtils.saveSettings();
|
mBgSourceUtils.saveSettings();
|
||||||
doubleRefreshPreview();
|
doubleRefreshPreview();
|
||||||
|
isPreviewBackgroundChanged = true;
|
||||||
ToastUtils.show("像素颜色已清空");
|
ToastUtils.show("像素颜色已清空");
|
||||||
LogUtils.d(TAG, "【像素清空】旧颜色:" + oldColor);
|
LogUtils.d(TAG, "【像素清空】旧颜色:" + oldColor);
|
||||||
}
|
}
|
||||||
@@ -395,6 +371,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
|||||||
try {
|
try {
|
||||||
mBgSourceUtils.loadSettings();
|
mBgSourceUtils.loadSettings();
|
||||||
mBackgroundView.loadBackgroundBean(mBgSourceUtils.getPreviewBackgroundBean(), true);
|
mBackgroundView.loadBackgroundBean(mBgSourceUtils.getPreviewBackgroundBean(), true);
|
||||||
|
mBackgroundView.setBackgroundColor(mBgSourceUtils.getPreviewBackgroundBean().getPixelColor());
|
||||||
LogUtils.d(TAG, "【双重刷新】第一重完成");
|
LogUtils.d(TAG, "【双重刷新】第一重完成");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LogUtils.e(TAG, "【双重刷新】第一重异常:" + e.getMessage());
|
LogUtils.e(TAG, "【双重刷新】第一重异常:" + e.getMessage());
|
||||||
@@ -409,6 +386,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
|||||||
try {
|
try {
|
||||||
mBgSourceUtils.loadSettings();
|
mBgSourceUtils.loadSettings();
|
||||||
mBackgroundView.loadBackgroundBean(mBgSourceUtils.getPreviewBackgroundBean(), true);
|
mBackgroundView.loadBackgroundBean(mBgSourceUtils.getPreviewBackgroundBean(), true);
|
||||||
|
mBackgroundView.setBackgroundColor(mBgSourceUtils.getPreviewBackgroundBean().getPixelColor());
|
||||||
LogUtils.d(TAG, "【双重刷新】第二重完成");
|
LogUtils.d(TAG, "【双重刷新】第二重完成");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LogUtils.e(TAG, "【双重刷新】第二重异常:" + e.getMessage());
|
LogUtils.e(TAG, "【双重刷新】第二重异常:" + e.getMessage());
|
||||||
@@ -573,7 +551,12 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
|||||||
String action = intent.getAction();
|
String action = intent.getAction();
|
||||||
String type = intent.getType();
|
String type = intent.getType();
|
||||||
if (Intent.ACTION_SEND.equals(action) && type != null && isImageType(type)) {
|
if (Intent.ACTION_SEND.equals(action) && type != null && isImageType(type)) {
|
||||||
BackgroundPicturePreviewDialog dlg = new BackgroundPicturePreviewDialog(this);
|
BackgroundPicturePreviewDialog dlg = new BackgroundPicturePreviewDialog(this, new BackgroundPicturePreviewDialog.IOnRecivedPictureListener(){
|
||||||
|
@Override
|
||||||
|
public void onAcceptRecivedPicture(Uri uriRecivedPicture) {
|
||||||
|
ToastUtils.show(String.format("uriRecivedPicture %s", uriRecivedPicture));
|
||||||
|
}
|
||||||
|
});
|
||||||
dlg.show();
|
dlg.show();
|
||||||
LogUtils.d(TAG, "【分享处理】收到分享图片意图");
|
LogUtils.d(TAG, "【分享处理】收到分享图片意图");
|
||||||
return true;
|
return true;
|
||||||
@@ -802,7 +785,7 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
|||||||
* 将 Uri 文件同步到预览 Bean
|
* 将 Uri 文件同步到预览 Bean
|
||||||
*/
|
*/
|
||||||
boolean putUriFileToPreviewSource(Uri srcUriFile) {
|
boolean putUriFileToPreviewSource(Uri srcUriFile) {
|
||||||
String filePath = UriUtil.getFilePathFromUri(this, srcUriFile);
|
String filePath = UriUtils.getFilePathFromUri(this, srcUriFile);
|
||||||
if (TextUtils.isEmpty(filePath)) {
|
if (TextUtils.isEmpty(filePath)) {
|
||||||
LogUtils.e(TAG, "putUriFileToPreviewSource: Uri解析路径为空");
|
LogUtils.e(TAG, "putUriFileToPreviewSource: Uri解析路径为空");
|
||||||
return false;
|
return false;
|
||||||
@@ -877,11 +860,9 @@ public class BackgroundSettingsActivity extends WinBoLLActivity implements Backg
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ====================== 接口实现 ======================
|
private void handlePixelPickerResult(int requestCode, int resultCode, Intent data) {
|
||||||
@Override
|
doubleRefreshPreview();
|
||||||
public void onAcceptRecivedPicture(String szPreRecivedPictureName) {
|
isPreviewBackgroundChanged = true;
|
||||||
ToastUtils.show("图片接收功能暂未实现");
|
}
|
||||||
LogUtils.d(TAG, "【分享接收】图片名:" + szPreRecivedPictureName);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import cc.winboll.studio.libappbase.LogUtils;
|
|||||||
import cc.winboll.studio.libappbase.ToastUtils;
|
import cc.winboll.studio.libappbase.ToastUtils;
|
||||||
import cc.winboll.studio.powerbell.App;
|
import cc.winboll.studio.powerbell.App;
|
||||||
import cc.winboll.studio.powerbell.R;
|
import cc.winboll.studio.powerbell.R;
|
||||||
import cc.winboll.studio.powerbell.model.BatteryInfoBean;
|
import cc.winboll.studio.powerbell.models.BatteryInfoBean;
|
||||||
import cc.winboll.studio.powerbell.receivers.ControlCenterServiceReceiver;
|
import cc.winboll.studio.powerbell.receivers.ControlCenterServiceReceiver;
|
||||||
import cc.winboll.studio.powerbell.utils.AppCacheUtils;
|
import cc.winboll.studio.powerbell.utils.AppCacheUtils;
|
||||||
import cc.winboll.studio.powerbell.utils.StringUtils;
|
import cc.winboll.studio.powerbell.utils.StringUtils;
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import cc.winboll.studio.libappbase.GlobalApplication;
|
|||||||
import cc.winboll.studio.powerbell.R;
|
import cc.winboll.studio.powerbell.R;
|
||||||
import cc.winboll.studio.powerbell.activities.BackgroundSettingsActivity;
|
import cc.winboll.studio.powerbell.activities.BackgroundSettingsActivity;
|
||||||
import cc.winboll.studio.powerbell.activities.PixelPickerActivity;
|
import cc.winboll.studio.powerbell.activities.PixelPickerActivity;
|
||||||
import cc.winboll.studio.powerbell.model.BackgroundBean;
|
import cc.winboll.studio.powerbell.models.BackgroundBean;
|
||||||
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
|
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
@@ -194,7 +194,7 @@ public class PixelPickerActivity extends WinBoLLActivity implements IWinBoLLActi
|
|||||||
dialog.dismiss();
|
dialog.dismiss();
|
||||||
// 可以在这里添加确定后的回调逻辑
|
// 可以在这里添加确定后的回调逻辑
|
||||||
BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(PixelPickerActivity.this);
|
BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(PixelPickerActivity.this);
|
||||||
BackgroundBean bean = utils.getCurrentBackgroundBean();
|
BackgroundBean bean = utils.getPreviewBackgroundBean();
|
||||||
bean.setPixelColor(pixelColor);
|
bean.setPixelColor(pixelColor);
|
||||||
utils.saveSettings();
|
utils.saveSettings();
|
||||||
Toast.makeText(PixelPickerActivity.this, "已记录像素值", Toast.LENGTH_SHORT).show();
|
Toast.makeText(PixelPickerActivity.this, "已记录像素值", Toast.LENGTH_SHORT).show();
|
||||||
@@ -218,7 +218,7 @@ public class PixelPickerActivity extends WinBoLLActivity implements IWinBoLLActi
|
|||||||
|
|
||||||
void setBackgroundColor() {
|
void setBackgroundColor() {
|
||||||
BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(PixelPickerActivity.this);
|
BackgroundSourceUtils utils = BackgroundSourceUtils.getInstance(PixelPickerActivity.this);
|
||||||
BackgroundBean bean = utils.getCurrentBackgroundBean();
|
BackgroundBean bean = utils.getPreviewBackgroundBean();
|
||||||
int nPixelColor = bean.getPixelColor();
|
int nPixelColor = bean.getPixelColor();
|
||||||
RelativeLayout mainLayout = findViewById(R.id.activitypixelpickerRelativeLayout1);
|
RelativeLayout mainLayout = findViewById(R.id.activitypixelpickerRelativeLayout1);
|
||||||
mainLayout.setBackgroundColor(nPixelColor);
|
mainLayout.setBackgroundColor(nPixelColor);
|
||||||
@@ -247,9 +247,11 @@ public class PixelPickerActivity extends WinBoLLActivity implements IWinBoLLActi
|
|||||||
@Override
|
@Override
|
||||||
public void onBackPressed() {
|
public void onBackPressed() {
|
||||||
super.onBackPressed();
|
super.onBackPressed();
|
||||||
Intent intent = new Intent();
|
setResult(RESULT_OK);
|
||||||
intent.setClass(this, BackgroundSettingsActivity.class);
|
finish();
|
||||||
startActivity(intent);
|
// Intent intent = new Intent();
|
||||||
|
// intent.setClass(this, BackgroundSettingsActivity.class);
|
||||||
|
// startActivity(intent);
|
||||||
//GlobalApplication.getWinBoLLActivityManager().startWinBoLLActivity(getApplicationContext(), BackgroundPictureActivity.class);
|
//GlobalApplication.getWinBoLLActivityManager().startWinBoLLActivity(getApplicationContext(), BackgroundPictureActivity.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,9 +6,7 @@ import android.view.View;
|
|||||||
import androidx.appcompat.widget.Toolbar;
|
import androidx.appcompat.widget.Toolbar;
|
||||||
import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity;
|
import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity;
|
||||||
import cc.winboll.studio.libappbase.LogUtils;
|
import cc.winboll.studio.libappbase.LogUtils;
|
||||||
import cc.winboll.studio.libappbase.ToastUtils;
|
|
||||||
import cc.winboll.studio.powerbell.R;
|
import cc.winboll.studio.powerbell.R;
|
||||||
import cc.winboll.studio.powerbell.utils.PermissionUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
|
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
|
||||||
@@ -50,18 +48,4 @@ public class SettingsActivity extends WinBoLLActivity implements IWinBoLLActivit
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onCheckPermission(View view) {
|
|
||||||
//ToastUtils.show("onCheckPermission");
|
|
||||||
PermissionUtils.getInstance().checkAndRequestMediaImagesPermission(this, REQUEST_READ_MEDIA_IMAGES);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
|
||||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
|
||||||
if (requestCode == REQUEST_READ_MEDIA_IMAGES) {
|
|
||||||
PermissionUtils.getInstance().handleStoragePermissionResult(this, requestCode, permissions, grantResults);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import android.widget.TextView;
|
|||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import cc.winboll.studio.powerbell.R;
|
import cc.winboll.studio.powerbell.R;
|
||||||
import cc.winboll.studio.powerbell.adapters.BatteryAdapter;
|
import cc.winboll.studio.powerbell.adapters.BatteryAdapter;
|
||||||
import cc.winboll.studio.powerbell.model.BatteryData;
|
import cc.winboll.studio.powerbell.models.BatteryData;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|||||||
@@ -2,22 +2,19 @@ package cc.winboll.studio.powerbell.dialogs;
|
|||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
import cc.winboll.studio.libappbase.LogUtils;
|
import cc.winboll.studio.libappbase.LogUtils;
|
||||||
import cc.winboll.studio.powerbell.MainActivity;
|
import cc.winboll.studio.powerbell.MainActivity;
|
||||||
import cc.winboll.studio.powerbell.R;
|
import cc.winboll.studio.powerbell.R;
|
||||||
import cc.winboll.studio.powerbell.activities.BackgroundSettingsActivity;
|
import cc.winboll.studio.powerbell.activities.BackgroundSettingsActivity;
|
||||||
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
|
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
|
||||||
import cc.winboll.studio.powerbell.utils.FileUtils;
|
import cc.winboll.studio.powerbell.utils.UriUtils;
|
||||||
import cc.winboll.studio.powerbell.utils.UriUtil;
|
import cc.winboll.studio.powerbell.views.BackgroundView;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author ZhanGSKen<zhangsken@qq.com>
|
* @Author ZhanGSKen<zhangsken@qq.com>
|
||||||
@@ -29,21 +26,25 @@ public class BackgroundPicturePreviewDialog extends Dialog {
|
|||||||
public static final String TAG = "BackgroundPicturePreviewDialog";
|
public static final String TAG = "BackgroundPicturePreviewDialog";
|
||||||
|
|
||||||
Context mContext;
|
Context mContext;
|
||||||
BackgroundSourceUtils mBackgroundPictureUtils;
|
//BackgroundSourceUtils mBackgroundPictureUtils;
|
||||||
Button dialogbackgroundpicturepreviewButton1;
|
Button dialogbackgroundpicturepreviewButton1;
|
||||||
Button dialogbackgroundpicturepreviewButton2;
|
Button dialogbackgroundpicturepreviewButton2;
|
||||||
String mszPreReceivedFileName;
|
//String mszPreReceivedFileName;
|
||||||
|
IOnRecivedPictureListener mIOnRecivedPictureListener;
|
||||||
|
Uri mUriRecivedPicture;
|
||||||
|
BackgroundView mBackgroundView;
|
||||||
|
|
||||||
public BackgroundPicturePreviewDialog(Context context) {
|
public BackgroundPicturePreviewDialog(Context context, IOnRecivedPictureListener iOnRecivedPictureListener) {
|
||||||
super(context);
|
super(context);
|
||||||
setContentView(R.layout.dialog_backgroundpicturepreview);
|
setContentView(R.layout.dialog_backgroundpicturepreview);
|
||||||
initEnv();
|
mIOnRecivedPictureListener = iOnRecivedPictureListener;
|
||||||
|
//initEnv();
|
||||||
|
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mBackgroundPictureUtils = BackgroundSourceUtils.getInstance(mContext);
|
//mBackgroundPictureUtils = BackgroundSourceUtils.getInstance(mContext);
|
||||||
|
|
||||||
ImageView imageView = findViewById(R.id.dialogbackgroundpicturepreviewImageView1);
|
mBackgroundView = findViewById(R.id.backgroundview);
|
||||||
copyAndViewRecivePicture(imageView);
|
previewRecivedPicture();
|
||||||
|
|
||||||
dialogbackgroundpicturepreviewButton1 = findViewById(R.id.dialogbackgroundpicturepreviewButton1);
|
dialogbackgroundpicturepreviewButton1 = findViewById(R.id.dialogbackgroundpicturepreviewButton1);
|
||||||
dialogbackgroundpicturepreviewButton1.setOnClickListener(new View.OnClickListener() {
|
dialogbackgroundpicturepreviewButton1.setOnClickListener(new View.OnClickListener() {
|
||||||
@@ -53,6 +54,7 @@ public class BackgroundPicturePreviewDialog extends Dialog {
|
|||||||
// 跳转到主窗口
|
// 跳转到主窗口
|
||||||
Intent i = new Intent(mContext, MainActivity.class);
|
Intent i = new Intent(mContext, MainActivity.class);
|
||||||
mContext.startActivity(i);
|
mContext.startActivity(i);
|
||||||
|
dismiss();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -62,79 +64,77 @@ public class BackgroundPicturePreviewDialog extends Dialog {
|
|||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
// 使用分享到的图片
|
// 使用分享到的图片
|
||||||
//
|
mIOnRecivedPictureListener.onAcceptRecivedPicture(mUriRecivedPicture);
|
||||||
//LogUtils.d(TAG, "mszReceivedFileName : " + mszReceivedFileName);
|
|
||||||
((IOnRecivedPictureListener)mContext).onAcceptRecivedPicture(mszPreReceivedFileName);
|
|
||||||
// 关闭对话框
|
// 关闭对话框
|
||||||
dismiss();
|
dismiss();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void initEnv() {
|
// void initEnv() {
|
||||||
LogUtils.d(TAG, "initEnv()");
|
// LogUtils.d(TAG, "initEnv()");
|
||||||
mszPreReceivedFileName = "PreReceived.data";
|
// mszPreReceivedFileName = "PreReceived.data";
|
||||||
}
|
// }
|
||||||
|
|
||||||
void copyAndViewRecivePicture(ImageView imageView) {
|
void previewRecivedPicture() {
|
||||||
//AppConfigUtils appConfigUtils = AppConfigUtils.getInstance((GlobalApplication)mContext.getApplicationContext());
|
|
||||||
BackgroundSettingsActivity activity = ((BackgroundSettingsActivity)mContext);
|
BackgroundSettingsActivity activity = ((BackgroundSettingsActivity)mContext);
|
||||||
|
|
||||||
//取出文件uri
|
//取出文件uri
|
||||||
Uri uri = activity.getIntent().getData();
|
mUriRecivedPicture = activity.getIntent().getData();
|
||||||
if (uri == null) {
|
if (mUriRecivedPicture == null) {
|
||||||
uri = activity.getIntent().getParcelableExtra(Intent.EXTRA_STREAM);
|
mUriRecivedPicture = activity.getIntent().getParcelableExtra(Intent.EXTRA_STREAM);
|
||||||
}
|
}
|
||||||
//获取文件真实地址
|
//获取文件真实地址
|
||||||
String szSrcImage = UriUtil.getFilePathFromUri(mContext, uri);
|
String szSrcImage = UriUtils.getFilePathFromUri(mContext, mUriRecivedPicture);
|
||||||
if (TextUtils.isEmpty(szSrcImage)) {
|
if (TextUtils.isEmpty(szSrcImage)) {
|
||||||
Toast.makeText(mContext, "接收到的文件为空。", Toast.LENGTH_SHORT).show();
|
Toast.makeText(mContext, "接收到的文件为空。", Toast.LENGTH_SHORT).show();
|
||||||
dismiss();
|
dismiss();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
mBackgroundView.loadImage(szSrcImage);
|
||||||
File fSrcImage = new File(szSrcImage);
|
//
|
||||||
//mszPreReceivedFileName = DateUtils.getDateNowString() + "-" + fSrcImage.getName();
|
// File fSrcImage = new File(szSrcImage);
|
||||||
File mfPreReceivedPhoto = new File(BackgroundSourceUtils.getInstance(mContext).getBackgroundSourceDirPath(), mszPreReceivedFileName);
|
// //mszPreReceivedFileName = DateUtils.getDateNowString() + "-" + fSrcImage.getName();
|
||||||
// 复制源图片到剪裁文件
|
// File mfPreReceivedPhoto = new File(BackgroundSourceUtils.getInstance(mContext).getBackgroundSourceDirPath(), mszPreReceivedFileName);
|
||||||
try {
|
// // 复制源图片到剪裁文件
|
||||||
FileUtils.copyFileUsingFileChannels(fSrcImage, mfPreReceivedPhoto);
|
// try {
|
||||||
LogUtils.d(TAG, "copyFileUsingFileChannels");
|
// FileUtils.copyFileUsingFileChannels(fSrcImage, mfPreReceivedPhoto);
|
||||||
Drawable drawable = Drawable.createFromPath(mfPreReceivedPhoto.getPath());
|
// LogUtils.d(TAG, "copyFileUsingFileChannels");
|
||||||
imageView.setBackground(drawable);
|
// Drawable drawable = Drawable.createFromPath(mfPreReceivedPhoto.getPath());
|
||||||
//LogUtils.d(TAG, "mszPreReceivedFileName : " + mszPreReceivedFileName);
|
// imageView.setBackground(drawable);
|
||||||
} catch (IOException e) {
|
// //LogUtils.d(TAG, "mszPreReceivedFileName : " + mszPreReceivedFileName);
|
||||||
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
|
// } catch (IOException e) {
|
||||||
}
|
// LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// 创建图片背景图片目录
|
// 创建图片背景图片目录
|
||||||
//
|
//
|
||||||
boolean createBackgroundFolder2(String szBackgroundFolder) {
|
// boolean createBackgroundFolder2(String szBackgroundFolder) {
|
||||||
// 文件路径参数为空值或无效值时返回false.
|
// // 文件路径参数为空值或无效值时返回false.
|
||||||
if (szBackgroundFolder == null | szBackgroundFolder.equals("")) {
|
// if (szBackgroundFolder == null | szBackgroundFolder.equals("")) {
|
||||||
return false;
|
// return false;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
LogUtils.d(TAG, "Background Folder Is : " + szBackgroundFolder);
|
// LogUtils.d(TAG, "Background Folder Is : " + szBackgroundFolder);
|
||||||
File f = new File(szBackgroundFolder);
|
// File f = new File(szBackgroundFolder);
|
||||||
if (f.exists()) {
|
// if (f.exists()) {
|
||||||
if (f.isDirectory()) {
|
// if (f.isDirectory()) {
|
||||||
return true;
|
// return true;
|
||||||
} else {
|
// } else {
|
||||||
// 工作路径不是一个目录
|
// // 工作路径不是一个目录
|
||||||
LogUtils.d(TAG, "createImageWorkFolder() error : szImageCacheFolder isDirectory return false. -->" + szBackgroundFolder);
|
// LogUtils.d(TAG, "createImageWorkFolder() error : szImageCacheFolder isDirectory return false. -->" + szBackgroundFolder);
|
||||||
return false;
|
// return false;
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
return f.mkdirs();
|
// return f.mkdirs();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
public interface IOnRecivedPictureListener {
|
public interface IOnRecivedPictureListener {
|
||||||
void onAcceptRecivedPicture(String szBackgroundFileName);
|
void onAcceptRecivedPicture(Uri uriRecivedPicture);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import cc.winboll.studio.libappbase.LogUtils;
|
|||||||
import cc.winboll.studio.powerbell.App;
|
import cc.winboll.studio.powerbell.App;
|
||||||
import cc.winboll.studio.powerbell.R;
|
import cc.winboll.studio.powerbell.R;
|
||||||
import cc.winboll.studio.powerbell.activities.PixelPickerActivity;
|
import cc.winboll.studio.powerbell.activities.PixelPickerActivity;
|
||||||
import cc.winboll.studio.powerbell.model.BackgroundBean;
|
import cc.winboll.studio.powerbell.models.BackgroundBean;
|
||||||
import cc.winboll.studio.powerbell.services.ControlCenterService;
|
import cc.winboll.studio.powerbell.services.ControlCenterService;
|
||||||
import cc.winboll.studio.powerbell.utils.AppConfigUtils;
|
import cc.winboll.studio.powerbell.utils.AppConfigUtils;
|
||||||
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
|
import cc.winboll.studio.powerbell.utils.BackgroundSourceUtils;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package cc.winboll.studio.powerbell.model;
|
package cc.winboll.studio.powerbell.models;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author ZhanGSKen<zhangsken@qq.com>
|
* @Author ZhanGSKen<zhangsken@qq.com>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package cc.winboll.studio.powerbell.model;
|
package cc.winboll.studio.powerbell.models;
|
||||||
|
|
||||||
import android.util.JsonReader;
|
import android.util.JsonReader;
|
||||||
import android.util.JsonWriter;
|
import android.util.JsonWriter;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package cc.winboll.studio.powerbell.model;
|
package cc.winboll.studio.powerbell.models;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author ZhanGSKen<zhangsken@qq.com>
|
* @Author ZhanGSKen<zhangsken@qq.com>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package cc.winboll.studio.powerbell.model;
|
package cc.winboll.studio.powerbell.models;
|
||||||
|
|
||||||
import android.util.JsonReader;
|
import android.util.JsonReader;
|
||||||
import android.util.JsonWriter;
|
import android.util.JsonWriter;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package cc.winboll.studio.powerbell.model;
|
package cc.winboll.studio.powerbell.models;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author ZhanGSKen<zhangsken@qq.com>
|
* @Author ZhanGSKen<zhangsken@qq.com>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package cc.winboll.studio.powerbell.model;
|
package cc.winboll.studio.powerbell.models;
|
||||||
|
|
||||||
// 应用消息结构
|
// 应用消息结构
|
||||||
//
|
//
|
||||||
@@ -5,7 +5,7 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import cc.winboll.studio.libappbase.LogUtils;
|
import cc.winboll.studio.libappbase.LogUtils;
|
||||||
import cc.winboll.studio.powerbell.model.AppConfigBean;
|
import cc.winboll.studio.powerbell.models.AppConfigBean;
|
||||||
import cc.winboll.studio.powerbell.services.ControlCenterService;
|
import cc.winboll.studio.powerbell.services.ControlCenterService;
|
||||||
import cc.winboll.studio.powerbell.utils.AppConfigUtils;
|
import cc.winboll.studio.powerbell.utils.AppConfigUtils;
|
||||||
import cc.winboll.studio.powerbell.utils.BatteryUtils;
|
import cc.winboll.studio.powerbell.utils.BatteryUtils;
|
||||||
|
|||||||
@@ -23,15 +23,15 @@ import cc.winboll.studio.libappbase.ToastUtils;
|
|||||||
import cc.winboll.studio.powerbell.App;
|
import cc.winboll.studio.powerbell.App;
|
||||||
import cc.winboll.studio.powerbell.MainActivity;
|
import cc.winboll.studio.powerbell.MainActivity;
|
||||||
import cc.winboll.studio.powerbell.R;
|
import cc.winboll.studio.powerbell.R;
|
||||||
import cc.winboll.studio.powerbell.model.AppConfigBean;
|
|
||||||
import cc.winboll.studio.powerbell.model.NotificationMessage;
|
|
||||||
import cc.winboll.studio.powerbell.handlers.ControlCenterServiceHandler;
|
import cc.winboll.studio.powerbell.handlers.ControlCenterServiceHandler;
|
||||||
|
import cc.winboll.studio.powerbell.models.AppConfigBean;
|
||||||
|
import cc.winboll.studio.powerbell.models.NotificationMessage;
|
||||||
import cc.winboll.studio.powerbell.receivers.ControlCenterServiceReceiver;
|
import cc.winboll.studio.powerbell.receivers.ControlCenterServiceReceiver;
|
||||||
import cc.winboll.studio.powerbell.services.AssistantService;
|
import cc.winboll.studio.powerbell.services.AssistantService;
|
||||||
import cc.winboll.studio.powerbell.threads.RemindThread;
|
import cc.winboll.studio.powerbell.threads.RemindThread;
|
||||||
import cc.winboll.studio.powerbell.utils.AppCacheUtils;
|
import cc.winboll.studio.powerbell.utils.AppCacheUtils;
|
||||||
import cc.winboll.studio.powerbell.utils.AppConfigUtils;
|
import cc.winboll.studio.powerbell.utils.AppConfigUtils;
|
||||||
import cc.winboll.studio.powerbell.utils.NotificationHelper;
|
import cc.winboll.studio.powerbell.utils.NotificationManagerUtils;
|
||||||
import cc.winboll.studio.powerbell.utils.ServiceUtils;
|
import cc.winboll.studio.powerbell.utils.ServiceUtils;
|
||||||
import cc.winboll.studio.powerbell.utils.StringUtils;
|
import cc.winboll.studio.powerbell.utils.StringUtils;
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ public class ControlCenterService extends Service {
|
|||||||
AppConfigUtils mAppConfigUtils;
|
AppConfigUtils mAppConfigUtils;
|
||||||
AppCacheUtils mAppCacheUtils;
|
AppCacheUtils mAppCacheUtils;
|
||||||
// 前台服务通知工具
|
// 前台服务通知工具
|
||||||
NotificationHelper mNotificationHelper;
|
NotificationManagerUtils mNotificationManagerUtils;
|
||||||
Notification notification;
|
Notification notification;
|
||||||
RemindThread mRemindThread;
|
RemindThread mRemindThread;
|
||||||
ControlCenterServiceHandler mControlCenterServiceHandler;
|
ControlCenterServiceHandler mControlCenterServiceHandler;
|
||||||
@@ -72,7 +72,7 @@ public class ControlCenterService extends Service {
|
|||||||
isServiceRunning = false;
|
isServiceRunning = false;
|
||||||
mAppConfigUtils = App.getAppConfigUtils(this);
|
mAppConfigUtils = App.getAppConfigUtils(this);
|
||||||
mAppCacheUtils = App.getAppCacheUtils(this);
|
mAppCacheUtils = App.getAppCacheUtils(this);
|
||||||
mNotificationHelper = new NotificationHelper(ControlCenterService.this);
|
mNotificationManagerUtils = new NotificationManagerUtils(ControlCenterService.this);
|
||||||
|
|
||||||
|
|
||||||
if (mMyServiceConnection == null) {
|
if (mMyServiceConnection == null) {
|
||||||
@@ -101,10 +101,10 @@ public class ControlCenterService extends Service {
|
|||||||
wakeupAndBindAssistant();
|
wakeupAndBindAssistant();
|
||||||
// 显示前台通知栏
|
// 显示前台通知栏
|
||||||
// 在Service中
|
// 在Service中
|
||||||
NotificationHelper helper = new NotificationHelper(this);
|
NotificationManagerUtils notificationManagerUtils = new NotificationManagerUtils(this);
|
||||||
Intent intent = new Intent(this, MainActivity.class);
|
//Intent intent = new Intent(this, MainActivity.class);
|
||||||
notification = helper.showForegroundNotification(intent, getString(R.string.app_name), "Service Running, Click to open app");
|
notificationManagerUtils.startForegroundServiceNotify(ControlCenterService.this, new NotificationMessage(getString(R.string.app_name), "Service Running, Click to open app"));
|
||||||
startForeground(NotificationHelper.FOREGROUND_NOTIFICATION_ID, notification);
|
//startForeground(NotificationHelper.FOREGROUND_NOTIFICATION_ID, notification);
|
||||||
|
|
||||||
// NotificationMessage notificationMessage=createNotificationMessage();
|
// NotificationMessage notificationMessage=createNotificationMessage();
|
||||||
// //Toast.makeText(getApplication(), "", Toast.LENGTH_SHORT).show();
|
// //Toast.makeText(getApplication(), "", Toast.LENGTH_SHORT).show();
|
||||||
@@ -260,9 +260,9 @@ public class ControlCenterService extends Service {
|
|||||||
for (int i = 0; i < 20; i++) {
|
for (int i = 0; i < 20; i++) {
|
||||||
msg += szRemindMSG;
|
msg += szRemindMSG;
|
||||||
}
|
}
|
||||||
NotificationHelper helper = new NotificationHelper(ControlCenterService.this);
|
NotificationManagerUtils notificationManagerUtils = new NotificationManagerUtils(ControlCenterService.this);
|
||||||
Intent intent = new Intent(ControlCenterService.this, MainActivity.class);
|
Intent intent = new Intent(ControlCenterService.this, MainActivity.class);
|
||||||
helper.showTemporaryNotification(intent, getString(R.string.app_name), msg);
|
notificationManagerUtils.showTempAlertNotify(getString(R.string.app_name), msg);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package cc.winboll.studio.powerbell.utils;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import cc.winboll.studio.libappbase.LogUtils;
|
import cc.winboll.studio.libappbase.LogUtils;
|
||||||
import cc.winboll.studio.powerbell.model.BatteryInfoBean;
|
import cc.winboll.studio.powerbell.models.BatteryInfoBean;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public class AppCacheUtils {
|
public class AppCacheUtils {
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import android.content.Context;
|
|||||||
import cc.winboll.studio.libappbase.LogUtils;
|
import cc.winboll.studio.libappbase.LogUtils;
|
||||||
import cc.winboll.studio.powerbell.App;
|
import cc.winboll.studio.powerbell.App;
|
||||||
import cc.winboll.studio.powerbell.MainActivity;
|
import cc.winboll.studio.powerbell.MainActivity;
|
||||||
import cc.winboll.studio.powerbell.model.AppConfigBean;
|
import cc.winboll.studio.powerbell.models.AppConfigBean;
|
||||||
import cc.winboll.studio.powerbell.model.ControlCenterServiceBean;
|
import cc.winboll.studio.powerbell.models.ControlCenterServiceBean;
|
||||||
import cc.winboll.studio.powerbell.dialogs.YesNoAlertDialog;
|
import cc.winboll.studio.powerbell.dialogs.YesNoAlertDialog;
|
||||||
import cc.winboll.studio.powerbell.fragments.MainViewFragment;
|
import cc.winboll.studio.powerbell.fragments.MainViewFragment;
|
||||||
import cc.winboll.studio.powerbell.services.ControlCenterService;
|
import cc.winboll.studio.powerbell.services.ControlCenterService;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import androidx.core.content.FileProvider;
|
|||||||
import cc.winboll.studio.libappbase.LogUtils;
|
import cc.winboll.studio.libappbase.LogUtils;
|
||||||
import cc.winboll.studio.libappbase.ToastUtils;
|
import cc.winboll.studio.libappbase.ToastUtils;
|
||||||
import cc.winboll.studio.powerbell.BuildConfig;
|
import cc.winboll.studio.powerbell.BuildConfig;
|
||||||
import cc.winboll.studio.powerbell.model.BackgroundBean;
|
import cc.winboll.studio.powerbell.models.BackgroundBean;
|
||||||
import java.io.BufferedOutputStream;
|
import java.io.BufferedOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
@@ -185,7 +185,7 @@ public class BackgroundSourceUtils {
|
|||||||
LogUtils.d(TAG, "【checkEmptyBackgroundAndCreateBlankBackgroundBean调用】开始检查背景Bean");
|
LogUtils.d(TAG, "【checkEmptyBackgroundAndCreateBlankBackgroundBean调用】开始检查背景Bean");
|
||||||
File fCheckBackgroundFile = new File(checkBackgroundBean.getBackgroundFilePath());
|
File fCheckBackgroundFile = new File(checkBackgroundBean.getBackgroundFilePath());
|
||||||
if (!fCheckBackgroundFile.exists()) {
|
if (!fCheckBackgroundFile.exists()) {
|
||||||
String newCropFileName = "blank10x10";
|
String newCropFileName = genNewCropFileName();
|
||||||
String fileSuffix = "png";
|
String fileSuffix = "png";
|
||||||
mCropSourceFile = new File(fCropCacheDir, newCropFileName + "." + fileSuffix);
|
mCropSourceFile = new File(fCropCacheDir, newCropFileName + "." + fileSuffix);
|
||||||
mCropResultFile = new File(fCropCacheDir, "SelectCompress_" + newCropFileName + "." + fileSuffix);
|
mCropResultFile = new File(fCropCacheDir, "SelectCompress_" + newCropFileName + "." + fileSuffix);
|
||||||
@@ -211,6 +211,10 @@ public class BackgroundSourceUtils {
|
|||||||
LogUtils.d(TAG, "背景Bean文件存在,无需创建空白背景");
|
LogUtils.d(TAG, "背景Bean文件存在,无需创建空白背景");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String genNewCropFileName() {
|
||||||
|
return UUID.randomUUID().toString() + System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建并更新预览剪裁环境
|
* 创建并更新预览剪裁环境
|
||||||
@@ -226,9 +230,9 @@ public class BackgroundSourceUtils {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Uri uri = UriUtil.getUriForFile(mContext, oldPreviewBackgroundBean.getBackgroundFilePath());
|
Uri uri = UriUtils.getUriForFile(mContext, oldPreviewBackgroundBean.getBackgroundFilePath());
|
||||||
String fileSuffix = FileUtils.getFileSuffix(mContext, uri);
|
String fileSuffix = FileUtils.getFileSuffix(mContext, uri);
|
||||||
String newCropFileName = UUID.randomUUID().toString() + System.currentTimeMillis();
|
String newCropFileName = genNewCropFileName();
|
||||||
mCropSourceFile = new File(fCropCacheDir, newCropFileName + "." + fileSuffix);
|
mCropSourceFile = new File(fCropCacheDir, newCropFileName + "." + fileSuffix);
|
||||||
mCropResultFile = new File(fCropCacheDir, "SelectCompress_" + newCropFileName + "." + fileSuffix);
|
mCropResultFile = new File(fCropCacheDir, "SelectCompress_" + newCropFileName + "." + fileSuffix);
|
||||||
|
|
||||||
@@ -415,6 +419,7 @@ public class BackgroundSourceUtils {
|
|||||||
*/
|
*/
|
||||||
public void commitPreviewSourceToCurrent() {
|
public void commitPreviewSourceToCurrent() {
|
||||||
LogUtils.d(TAG, "【commitPreviewSourceToCurrent调用】开始深拷贝预览Bean到正式Bean");
|
LogUtils.d(TAG, "【commitPreviewSourceToCurrent调用】开始深拷贝预览Bean到正式Bean");
|
||||||
|
//ToastUtils.show("【commitPreviewSourceToCurrent调用】开始深拷贝预览Bean到正式Bean");
|
||||||
currentBackgroundBean = new BackgroundBean();
|
currentBackgroundBean = new BackgroundBean();
|
||||||
currentBackgroundBean.setBackgroundFileName(previewBackgroundBean.getBackgroundFileName());
|
currentBackgroundBean.setBackgroundFileName(previewBackgroundBean.getBackgroundFileName());
|
||||||
currentBackgroundBean.setBackgroundFilePath(previewBackgroundBean.getBackgroundFilePath());
|
currentBackgroundBean.setBackgroundFilePath(previewBackgroundBean.getBackgroundFilePath());
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import android.net.Uri;
|
|||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import androidx.core.content.FileProvider;
|
import androidx.core.content.FileProvider;
|
||||||
import cc.winboll.studio.libappbase.LogUtils;
|
import cc.winboll.studio.libappbase.LogUtils;
|
||||||
import cc.winboll.studio.powerbell.model.BackgroundBean;
|
import cc.winboll.studio.powerbell.models.BackgroundBean;
|
||||||
import com.yalantis.ucrop.UCrop;
|
import com.yalantis.ucrop.UCrop;
|
||||||
import com.yalantis.ucrop.UCropActivity;
|
import com.yalantis.ucrop.UCropActivity;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|||||||
@@ -1,151 +0,0 @@
|
|||||||
package cc.winboll.studio.powerbell.utils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Author ZhanGSKen<zhangsken@qq.com>
|
|
||||||
* @Date 2025/03/22 04:39:40
|
|
||||||
* @Describe 通知工具类
|
|
||||||
*/
|
|
||||||
import android.app.Notification;
|
|
||||||
import android.app.NotificationChannel;
|
|
||||||
import android.app.NotificationManager;
|
|
||||||
import android.app.PendingIntent;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.graphics.BitmapFactory;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.widget.RemoteViews;
|
|
||||||
import androidx.annotation.RequiresApi;
|
|
||||||
import androidx.core.app.NotificationCompat;
|
|
||||||
import cc.winboll.studio.powerbell.R;
|
|
||||||
|
|
||||||
public class NotificationHelper {
|
|
||||||
public static final String TAG = "NotificationHelper";
|
|
||||||
|
|
||||||
// 渠道ID和名称
|
|
||||||
private static final String CHANNEL_ID_FOREGROUND = "foreground_channel";
|
|
||||||
private static final String CHANNEL_NAME_FOREGROUND = "Foreground Service";
|
|
||||||
private static final String CHANNEL_ID_TEMPORARY = "temporary_channel";
|
|
||||||
private static final String CHANNEL_NAME_TEMPORARY = "Temporary Notifications";
|
|
||||||
|
|
||||||
// 通知ID
|
|
||||||
public static final int FOREGROUND_NOTIFICATION_ID = 1001;
|
|
||||||
public static final int TEMPORARY_NOTIFICATION_ID = 2001;
|
|
||||||
|
|
||||||
private final Context mContext;
|
|
||||||
private final NotificationManager mNotificationManager;
|
|
||||||
|
|
||||||
public NotificationHelper(Context context) {
|
|
||||||
mContext = context;
|
|
||||||
mNotificationManager = context.getSystemService(NotificationManager.class);
|
|
||||||
createNotificationChannels();
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
|
||||||
private void createNotificationChannels() {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
createForegroundChannel();
|
|
||||||
createTemporaryChannel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
|
||||||
private void createForegroundChannel() {
|
|
||||||
NotificationChannel channel = new NotificationChannel(
|
|
||||||
CHANNEL_ID_FOREGROUND,
|
|
||||||
CHANNEL_NAME_FOREGROUND,
|
|
||||||
NotificationManager.IMPORTANCE_LOW
|
|
||||||
);
|
|
||||||
channel.setDescription("Persistent service notifications");
|
|
||||||
channel.setSound(null, null);
|
|
||||||
channel.enableVibration(false);
|
|
||||||
mNotificationManager.createNotificationChannel(channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
|
||||||
private void createTemporaryChannel() {
|
|
||||||
NotificationChannel channel = new NotificationChannel(
|
|
||||||
CHANNEL_ID_TEMPORARY,
|
|
||||||
CHANNEL_NAME_TEMPORARY,
|
|
||||||
NotificationManager.IMPORTANCE_HIGH
|
|
||||||
);
|
|
||||||
channel.setDescription("Temporary alert notifications");
|
|
||||||
channel.setSound(null, null);
|
|
||||||
channel.enableVibration(true);
|
|
||||||
channel.setVibrationPattern(new long[]{100, 200, 300, 400});
|
|
||||||
channel.setBypassDnd(true);
|
|
||||||
mNotificationManager.createNotificationChannel(channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 显示常驻通知(通常用于前台服务)
|
|
||||||
public Notification showForegroundNotification(Intent intent, String title, String content) {
|
|
||||||
PendingIntent pendingIntent = createPendingIntent(intent);
|
|
||||||
|
|
||||||
Notification notification = new NotificationCompat.Builder(mContext, CHANNEL_ID_FOREGROUND)
|
|
||||||
.setSmallIcon(R.drawable.ic_launcher)
|
|
||||||
.setLargeIcon(BitmapFactory.decodeResource(mContext.getResources(), R.drawable.ic_launcher))
|
|
||||||
//.setContentTitle(title + "\n" + content)
|
|
||||||
.setContentTitle(content)
|
|
||||||
//.setContentText(content)
|
|
||||||
.setContentIntent(pendingIntent)
|
|
||||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
|
||||||
.setOngoing(true)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
mNotificationManager.notify(FOREGROUND_NOTIFICATION_ID, notification);
|
|
||||||
return notification;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 显示临时通知(自动消失)
|
|
||||||
public void showTemporaryNotification(Intent intent, String title, String content) {
|
|
||||||
PendingIntent pendingIntent = createPendingIntent(intent);
|
|
||||||
|
|
||||||
Notification notification = new NotificationCompat.Builder(mContext, CHANNEL_ID_TEMPORARY)
|
|
||||||
.setSmallIcon(R.drawable.ic_launcher)
|
|
||||||
.setLargeIcon(BitmapFactory.decodeResource(mContext.getResources(), R.drawable.ic_launcher))
|
|
||||||
.setContentTitle(title)
|
|
||||||
.setContentText(content)
|
|
||||||
.setContentIntent(pendingIntent)
|
|
||||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
|
||||||
.setAutoCancel(true)
|
|
||||||
.setVibrate(new long[]{100, 200, 300, 400})
|
|
||||||
.build();
|
|
||||||
|
|
||||||
mNotificationManager.notify(TEMPORARY_NOTIFICATION_ID, notification);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建自定义布局通知(可扩展)
|
|
||||||
public void showCustomNotification(Intent intent, RemoteViews contentView, RemoteViews bigContentView) {
|
|
||||||
PendingIntent pendingIntent = createPendingIntent(intent);
|
|
||||||
|
|
||||||
Notification notification = new NotificationCompat.Builder(mContext, CHANNEL_ID_TEMPORARY)
|
|
||||||
.setSmallIcon(R.drawable.ic_launcher)
|
|
||||||
.setContentIntent(pendingIntent)
|
|
||||||
.setContent(contentView)
|
|
||||||
.setCustomBigContentView(bigContentView)
|
|
||||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
|
||||||
.setAutoCancel(true)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
mNotificationManager.notify(TEMPORARY_NOTIFICATION_ID + 1, notification);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 取消所有通知
|
|
||||||
public void cancelAllNotifications() {
|
|
||||||
mNotificationManager.cancelAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建PendingIntent(兼容不同API版本)
|
|
||||||
private PendingIntent createPendingIntent(Intent intent) {
|
|
||||||
int flags = PendingIntent.FLAG_UPDATE_CURRENT;
|
|
||||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
||||||
// flags |= PendingIntent.FLAG_IMMUTABLE;
|
|
||||||
// }
|
|
||||||
return PendingIntent.getActivity(
|
|
||||||
mContext,
|
|
||||||
0,
|
|
||||||
intent,
|
|
||||||
flags
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -0,0 +1,416 @@
|
|||||||
|
package cc.winboll.studio.powerbell.utils;
|
||||||
|
|
||||||
|
import android.app.Notification;
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.graphics.BitmapFactory;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.media.RingtoneManager;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.RemoteViews;
|
||||||
|
import androidx.core.app.NotificationCompat;
|
||||||
|
import cc.winboll.studio.libappbase.LogUtils;
|
||||||
|
import cc.winboll.studio.powerbell.MainActivity;
|
||||||
|
import cc.winboll.studio.powerbell.R;
|
||||||
|
import cc.winboll.studio.powerbell.models.NotificationMessage;
|
||||||
|
import cc.winboll.studio.powerbell.services.ControlCenterService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
|
||||||
|
* @Date 2025/12/13 20:44
|
||||||
|
* @Describe 全局通知管理工具类(整合所有通知能力,适配API29-30,兼容Java7,所有通知统一跳转MainActivity)
|
||||||
|
*/
|
||||||
|
public class NotificationManagerUtils {
|
||||||
|
// ====================== 常量定义(统一管理,避免冲突,首屏可见)======================
|
||||||
|
public static final String TAG = "NotificationManagerUtils";
|
||||||
|
// 通知渠道(4大渠道,场景隔离,API26+必填)
|
||||||
|
// 1. 前台服务保活渠道(低优先级,无打扰)
|
||||||
|
private static final String CHANNEL_ID_FOREGROUND_SERVICE = "channel_foreground_service";
|
||||||
|
private static final String CHANNEL_NAME_FOREGROUND_SERVICE = "前台服务保活通知";
|
||||||
|
private static final String CHANNEL_DESC_FOREGROUND_SERVICE = "后台服务运行状态,无声音无震动,不打扰用户";
|
||||||
|
// 2. 电量提醒渠道(高优先级,闹钟铃声+震动,强提醒)
|
||||||
|
private static final String CHANNEL_ID_BATTERY_REMIND = "channel_battery_remind";
|
||||||
|
private static final String CHANNEL_NAME_BATTERY_REMIND = "电量异常提醒通知";
|
||||||
|
private static final String CHANNEL_DESC_BATTERY_REMIND = "电量过高/过低提醒,强震动+闹钟铃声,突破免打扰";
|
||||||
|
// 3. 通用临时通知渠道(高优先级,仅震动,普通告警)
|
||||||
|
private static final String CHANNEL_ID_TEMP_ALERT = "channel_temp_alert";
|
||||||
|
private static final String CHANNEL_NAME_TEMP_ALERT = "通用临时提醒通知";
|
||||||
|
private static final String CHANNEL_DESC_TEMP_ALERT = "普通即时告警,仅震动提醒,自动取消";
|
||||||
|
// 通知ID(唯一区分,避免覆盖,按场景分段)
|
||||||
|
public static final int NOTIFY_ID_FOREGROUND_SERVICE = 1001; // 前台服务
|
||||||
|
public static final int NOTIFY_ID_BATTERY_REMIND = 1002; // 电量提醒
|
||||||
|
public static final int NOTIFY_ID_TEMP_ALERT = 1003; // 通用临时通知
|
||||||
|
public static final int NOTIFY_ID_CUSTOM_LAYOUT = 1004; // 自定义布局通知
|
||||||
|
// 通用配置
|
||||||
|
private static final int PENDING_INTENT_FLAGS = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
||||||
|
? PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
|
||||||
|
: PendingIntent.FLAG_UPDATE_CURRENT; // API30安全标志
|
||||||
|
private static final long[] VIBRATE_PATTERN = new long[]{100, 200, 300, 400}; // 标准震动节奏
|
||||||
|
//private static final String DEFAULT_JUMP_PACKAGE = "cc.winboll.studio.powerbell"; // 默认跳转包名(API29+必填)
|
||||||
|
|
||||||
|
// ====================== 成员变量(按场景分组,私有封装,避免外部篡改)======================
|
||||||
|
private final Context mContext;
|
||||||
|
private final NotificationManager mNotificationManager;
|
||||||
|
// 前台服务通知专属
|
||||||
|
private Notification mForegroundServiceNotify;
|
||||||
|
private RemoteViews mForegroundServiceRemoteViews;
|
||||||
|
// 电量提醒通知专属
|
||||||
|
private Notification mBatteryRemindNotify;
|
||||||
|
private RemoteViews mBatteryRemindRemoteViews;
|
||||||
|
|
||||||
|
// ====================== 构造方法(单例思想/实例化通用,自动初始化渠道)======================
|
||||||
|
public NotificationManagerUtils(Context context) {
|
||||||
|
LogUtils.d(TAG, "【初始化】全局通知管理工具类 构造方法调用");
|
||||||
|
this.mContext = context.getApplicationContext(); // 用应用上下文,避免内存泄漏
|
||||||
|
this.mNotificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
|
createAllNotificationChannels(); // 自动创建所有渠道(API26+)
|
||||||
|
LogUtils.d(TAG, "【初始化】全局通知管理工具类 完成,渠道创建状态:" + (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? "已创建4个渠道" : "无需创建"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 核心基础能力(渠道创建+Intent构建,复用逻辑,减少冗余)======================
|
||||||
|
/**
|
||||||
|
* 创建所有通知渠道(API26+专属,低版本自动跳过,确保通知正常显示)
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public void createAllNotificationChannels() {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
LogUtils.d(TAG, "【渠道管理】开始创建所有通知渠道");
|
||||||
|
createForegroundServiceChannel();
|
||||||
|
createBatteryRemindChannel();
|
||||||
|
createTempAlertChannel();
|
||||||
|
LogUtils.d(TAG, "【渠道管理】4个通知渠道创建完成(含3个核心渠道+预留扩展)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建前台服务保活渠道(IMPORTANCE_LOW,无声音无震动,不打扰用户)
|
||||||
|
*/
|
||||||
|
private void createForegroundServiceChannel() {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
NotificationChannel channel = new NotificationChannel(
|
||||||
|
CHANNEL_ID_FOREGROUND_SERVICE,
|
||||||
|
CHANNEL_NAME_FOREGROUND_SERVICE,
|
||||||
|
NotificationManager.IMPORTANCE_LOW
|
||||||
|
);
|
||||||
|
channel.setDescription(CHANNEL_DESC_FOREGROUND_SERVICE);
|
||||||
|
channel.setSound(null, null);
|
||||||
|
channel.enableVibration(false);
|
||||||
|
channel.setShowBadge(false); // 不显示应用角标
|
||||||
|
channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET); // 锁屏隐藏
|
||||||
|
mNotificationManager.createNotificationChannel(channel);
|
||||||
|
LogUtils.d(TAG, "【渠道管理】前台服务保活渠道创建成功:" + CHANNEL_NAME_FOREGROUND_SERVICE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建电量提醒渠道(IMPORTANCE_HIGH,闹钟铃声+震动,突破免打扰)
|
||||||
|
*/
|
||||||
|
private void createBatteryRemindChannel() {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
NotificationChannel channel = new NotificationChannel(
|
||||||
|
CHANNEL_ID_BATTERY_REMIND,
|
||||||
|
CHANNEL_NAME_BATTERY_REMIND,
|
||||||
|
NotificationManager.IMPORTANCE_HIGH
|
||||||
|
);
|
||||||
|
channel.setDescription(CHANNEL_DESC_BATTERY_REMIND);
|
||||||
|
channel.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION), null); // 闹钟铃声
|
||||||
|
channel.enableVibration(true);
|
||||||
|
channel.setVibrationPattern(VIBRATE_PATTERN);
|
||||||
|
channel.setBypassDnd(true); // 突破免打扰
|
||||||
|
channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC); // 锁屏可见
|
||||||
|
channel.setShowBadge(true);
|
||||||
|
mNotificationManager.createNotificationChannel(channel);
|
||||||
|
LogUtils.d(TAG, "【渠道管理】电量提醒渠道创建成功:" + CHANNEL_NAME_BATTERY_REMIND);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建通用临时通知渠道(IMPORTANCE_HIGH,仅震动,普通告警)
|
||||||
|
*/
|
||||||
|
private void createTempAlertChannel() {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
NotificationChannel channel = new NotificationChannel(
|
||||||
|
CHANNEL_ID_TEMP_ALERT,
|
||||||
|
CHANNEL_NAME_TEMP_ALERT,
|
||||||
|
NotificationManager.IMPORTANCE_HIGH
|
||||||
|
);
|
||||||
|
channel.setDescription(CHANNEL_DESC_TEMP_ALERT);
|
||||||
|
//channel.setSound(null, null); // 仅震动,不发声
|
||||||
|
channel.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION), null); // 闹钟铃声
|
||||||
|
channel.enableVibration(true);
|
||||||
|
channel.setVibrationPattern(VIBRATE_PATTERN);
|
||||||
|
channel.setBypassDnd(false); // 不突破免打扰
|
||||||
|
channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
|
||||||
|
channel.setShowBadge(true);
|
||||||
|
mNotificationManager.createNotificationChannel(channel);
|
||||||
|
LogUtils.d(TAG, "【渠道管理】通用临时通知渠道创建成功:" + CHANNEL_NAME_TEMP_ALERT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建固定跳转PendingIntent(所有通知统一跳转MainActivity,适配API29-30安全规范)
|
||||||
|
* @return 安全的PendingIntent,确保跳转稳定不泄露
|
||||||
|
*/
|
||||||
|
private PendingIntent buildFixedPendingIntent() {
|
||||||
|
// 固定跳MainActivity,不支持自定义目标
|
||||||
|
Intent intent = new Intent(mContext, MainActivity.class);
|
||||||
|
// API29+ 强制要求:明确包名,避免跳转目标模糊
|
||||||
|
intent.setPackage(mContext.getPackageName());
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); // 跳转时清除栈顶,避免重复创建Activity
|
||||||
|
LogUtils.d(TAG, "【Intent构建】所有通知统一跳转:MainActivity,包名:" + mContext.getPackageName());
|
||||||
|
|
||||||
|
PendingIntent pendingIntent = PendingIntent.getActivity(
|
||||||
|
mContext,
|
||||||
|
0,
|
||||||
|
intent,
|
||||||
|
PENDING_INTENT_FLAGS
|
||||||
|
);
|
||||||
|
LogUtils.d(TAG, "【Intent构建】PendingIntent创建成功,安全标志:" + PENDING_INTENT_FLAGS);
|
||||||
|
return pendingIntent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 场景1:前台服务保活通知(支持自定义布局+更新)======================
|
||||||
|
/**
|
||||||
|
* 初始化前台服务通知自定义布局(RemoteViews)
|
||||||
|
*/
|
||||||
|
private void initForegroundServiceRemoteViews(ControlCenterService service, NotificationMessage msg) {
|
||||||
|
LogUtils.d(TAG, "【布局初始化】开始初始化前台服务通知布局,标题:" + msg.getTitle());
|
||||||
|
mForegroundServiceRemoteViews = new RemoteViews(service.getPackageName(), R.layout.view_servicenotification);
|
||||||
|
mForegroundServiceRemoteViews.setTextViewText(R.id.remoteviewTextView1, msg.getTitle());
|
||||||
|
mForegroundServiceRemoteViews.setTextViewText(R.id.remoteviewTextView3, msg.getContent());
|
||||||
|
mForegroundServiceRemoteViews.setImageViewResource(R.id.remoteviewImageView1, R.drawable.ic_launcher);
|
||||||
|
LogUtils.d(TAG, "【布局初始化】前台服务通知布局填充完成");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动前台服务保活通知(ControlCenterService专用,API26+强制要求,保活后台服务)
|
||||||
|
*/
|
||||||
|
public void startForegroundServiceNotify(ControlCenterService service, NotificationMessage msg) {
|
||||||
|
LogUtils.d(TAG, "【前台服务通知】开始构建保活通知,内容:" + msg.getContent());
|
||||||
|
if (service == null || msg == null) {
|
||||||
|
LogUtils.e(TAG, "【前台服务通知】构建失败:Service/NotificationMessage为空");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. 构建固定跳转Intent(统一跳MainActivity)
|
||||||
|
PendingIntent pendingIntent = buildFixedPendingIntent();
|
||||||
|
// 2. 构建基础通知(兼容API26+渠道,低版本用Builder)
|
||||||
|
Notification.Builder builder;
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
builder = new Notification.Builder(service, CHANNEL_ID_FOREGROUND_SERVICE);
|
||||||
|
} else {
|
||||||
|
builder = new Notification.Builder(service);
|
||||||
|
}
|
||||||
|
mForegroundServiceNotify = builder
|
||||||
|
.setSmallIcon(R.drawable.ic_launcher)
|
||||||
|
.setLargeIcon(BitmapFactory.decodeResource(service.getResources(), R.drawable.ic_launcher))
|
||||||
|
.setContentTitle(msg.getTitle())
|
||||||
|
.setContentText(msg.getContent())
|
||||||
|
.setWhen(System.currentTimeMillis())
|
||||||
|
.setColor(Color.parseColor("#F00606")) // 小图标背景色
|
||||||
|
.setContentIntent(pendingIntent)
|
||||||
|
.setOngoing(true) // 常驻通知,不可滑动取消(保活关键)
|
||||||
|
.setAutoCancel(false) // 禁止点击取消
|
||||||
|
.build();
|
||||||
|
// 3. 设置自定义布局
|
||||||
|
initForegroundServiceRemoteViews(service, msg);
|
||||||
|
mForegroundServiceNotify.contentView = mForegroundServiceRemoteViews;
|
||||||
|
mForegroundServiceNotify.bigContentView = mForegroundServiceRemoteViews;
|
||||||
|
// 4. 启动前台服务(必须调用,否则Service易被回收)
|
||||||
|
service.startForeground(NOTIFY_ID_FOREGROUND_SERVICE, mForegroundServiceNotify);
|
||||||
|
LogUtils.d(TAG, "【前台服务通知】保活通知启动成功,通知ID:" + NOTIFY_ID_FOREGROUND_SERVICE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新前台服务保活通知内容(无需重启服务,直接刷新布局)
|
||||||
|
*/
|
||||||
|
public void updateForegroundServiceNotify(ControlCenterService service, NotificationMessage msg) {
|
||||||
|
LogUtils.d(TAG, "【前台服务通知】开始更新保活通知,新内容:" + msg.getContent());
|
||||||
|
if (mForegroundServiceNotify == null || mForegroundServiceRemoteViews == null) {
|
||||||
|
LogUtils.e(TAG, "【前台服务通知】更新失败:通知对象未初始化,先调用startForegroundServiceNotify");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 更新自定义布局数据
|
||||||
|
initForegroundServiceRemoteViews(service, msg);
|
||||||
|
mForegroundServiceNotify.contentView = mForegroundServiceRemoteViews;
|
||||||
|
mForegroundServiceNotify.bigContentView = mForegroundServiceRemoteViews;
|
||||||
|
// 发送更新
|
||||||
|
mNotificationManager.notify(NOTIFY_ID_FOREGROUND_SERVICE, mForegroundServiceNotify);
|
||||||
|
LogUtils.d(TAG, "【前台服务通知】保活通知更新成功");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 场景2:电量提醒通知(支持自定义布局+更新+单独取消)======================
|
||||||
|
/**
|
||||||
|
* 初始化电量提醒通知自定义布局(RemoteViews,支持充电/耗电切换)
|
||||||
|
*/
|
||||||
|
private void initBatteryRemindRemoteViews(ControlCenterService service, NotificationMessage msg) {
|
||||||
|
LogUtils.d(TAG, "【布局初始化】开始初始化电量提醒布局,提醒类型:" + msg.getRemindMSG());
|
||||||
|
mBatteryRemindRemoteViews = new RemoteViews(service.getPackageName(), R.layout.view_remindnotification);
|
||||||
|
mBatteryRemindRemoteViews.setTextViewText(R.id.viewremindnotificationTextView1, msg.getTitle());
|
||||||
|
mBatteryRemindRemoteViews.setImageViewResource(R.id.remoteviewImageView1, R.drawable.ic_launcher);
|
||||||
|
// 切换布局(+:充电提醒,-:耗电提醒)
|
||||||
|
String remindType = msg.getRemindMSG() != null ? msg.getRemindMSG().trim() : "";
|
||||||
|
if ("+".equals(remindType)) {
|
||||||
|
mBatteryRemindRemoteViews.setViewVisibility(R.id.remoteviewUsege, View.GONE);
|
||||||
|
mBatteryRemindRemoteViews.setViewVisibility(R.id.remoteviewCharge, View.VISIBLE);
|
||||||
|
LogUtils.d(TAG, "【布局初始化】电量提醒布局切换:充电提醒");
|
||||||
|
} else if ("-".equals(remindType)) {
|
||||||
|
mBatteryRemindRemoteViews.setViewVisibility(R.id.remoteviewCharge, View.GONE);
|
||||||
|
mBatteryRemindRemoteViews.setViewVisibility(R.id.remoteviewUsege, View.VISIBLE);
|
||||||
|
LogUtils.d(TAG, "【布局初始化】电量提醒布局切换:耗电提醒");
|
||||||
|
} else {
|
||||||
|
mBatteryRemindRemoteViews.setViewVisibility(R.id.remoteviewCharge, View.GONE);
|
||||||
|
mBatteryRemindRemoteViews.setViewVisibility(R.id.remoteviewUsege, View.VISIBLE);
|
||||||
|
LogUtils.w(TAG, "【布局初始化】未知电量提醒类型:" + remindType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化电量提醒通知(仅构建,不发送,配合update触发提醒)
|
||||||
|
*/
|
||||||
|
public void initBatteryRemindNotify(ControlCenterService service, NotificationMessage msg) {
|
||||||
|
LogUtils.d(TAG, "【电量提醒通知】开始初始化提醒通知,标题:" + msg.getTitle());
|
||||||
|
if (service == null || msg == null) {
|
||||||
|
LogUtils.e(TAG, "【电量提醒通知】初始化失败:Service/NotificationMessage为空");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 1. 构建固定跳转Intent(统一跳MainActivity)
|
||||||
|
PendingIntent pendingIntent = buildFixedPendingIntent();
|
||||||
|
// 2. 构建基础通知
|
||||||
|
Notification.Builder builder;
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
builder = new Notification.Builder(service, CHANNEL_ID_BATTERY_REMIND);
|
||||||
|
} else {
|
||||||
|
builder = new Notification.Builder(service);
|
||||||
|
}
|
||||||
|
mBatteryRemindNotify = builder
|
||||||
|
.setSmallIcon(R.drawable.ic_launcher)
|
||||||
|
.setLargeIcon(BitmapFactory.decodeResource(service.getResources(), R.drawable.ic_launcher))
|
||||||
|
.setContentTitle(msg.getTitle())
|
||||||
|
.setContentText(msg.getContent())
|
||||||
|
.setWhen(System.currentTimeMillis())
|
||||||
|
.setColor(Color.parseColor("#F00606"))
|
||||||
|
.setContentIntent(pendingIntent)
|
||||||
|
.setAutoCancel(true) // 点击取消
|
||||||
|
.build();
|
||||||
|
// 3. 初始化自定义布局
|
||||||
|
initBatteryRemindRemoteViews(service, msg);
|
||||||
|
mBatteryRemindNotify.contentView = mBatteryRemindRemoteViews;
|
||||||
|
mBatteryRemindNotify.bigContentView = mBatteryRemindRemoteViews;
|
||||||
|
LogUtils.d(TAG, "【电量提醒通知】初始化完成");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送/更新电量提醒通知(初始化后调用,触发强提醒)
|
||||||
|
*/
|
||||||
|
public void sendOrUpdateBatteryRemindNotify() {
|
||||||
|
LogUtils.d(TAG, "【电量提醒通知】开始发送/更新提醒");
|
||||||
|
if (mBatteryRemindNotify == null || mBatteryRemindRemoteViews == null) {
|
||||||
|
LogUtils.e(TAG, "【电量提醒通知】发送失败:通知未初始化,先调用initBatteryRemindNotify");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mNotificationManager.notify(NOTIFY_ID_BATTERY_REMIND, mBatteryRemindNotify);
|
||||||
|
LogUtils.d(TAG, "【电量提醒通知】发送/更新成功,通知ID:" + NOTIFY_ID_BATTERY_REMIND);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单独取消电量提醒通知(静态方法,外部可直接调用,无需实例化)
|
||||||
|
*/
|
||||||
|
public static void cancelBatteryRemindNotify(Context context) {
|
||||||
|
LogUtils.d(TAG, "【电量提醒通知】开始取消提醒,通知ID:" + NOTIFY_ID_BATTERY_REMIND);
|
||||||
|
if (context == null) {
|
||||||
|
LogUtils.e(TAG, "【电量提醒通知】取消失败:Context为空");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
|
manager.cancel(NOTIFY_ID_BATTERY_REMIND);
|
||||||
|
LogUtils.d(TAG, "【电量提醒通知】取消成功");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 场景3:通用临时通知(简单文本,自动取消,无需自定义布局)======================
|
||||||
|
/**
|
||||||
|
* 显示通用临时通知(普通告警,仅震动,自动取消,统一跳转MainActivity)
|
||||||
|
* @param title 通知标题
|
||||||
|
* @param content 通知内容
|
||||||
|
*/
|
||||||
|
public void showTempAlertNotify(String title, String content) {
|
||||||
|
LogUtils.d(TAG, "【通用临时通知】开始构建,标题:" + title + ",内容:" + content);
|
||||||
|
if (title == null || content == null) {
|
||||||
|
LogUtils.e(TAG, "【通用临时通知】构建失败:标题/内容为空");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 1. 构建固定跳转Intent(统一跳MainActivity)
|
||||||
|
PendingIntent pendingIntent = buildFixedPendingIntent();
|
||||||
|
// 2. 用NotificationCompat.Builder(兼容所有版本,简化逻辑)
|
||||||
|
NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext, CHANNEL_ID_TEMP_ALERT)
|
||||||
|
.setSmallIcon(R.drawable.ic_launcher)
|
||||||
|
.setLargeIcon(BitmapFactory.decodeResource(mContext.getResources(), R.drawable.ic_launcher))
|
||||||
|
.setContentTitle(title)
|
||||||
|
.setContentText(content)
|
||||||
|
.setWhen(System.currentTimeMillis())
|
||||||
|
.setContentIntent(pendingIntent)
|
||||||
|
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||||
|
.setAutoCancel(true)
|
||||||
|
.setVibrate(VIBRATE_PATTERN);
|
||||||
|
// 3. 发送通知
|
||||||
|
Notification notification = builder.build();
|
||||||
|
mNotificationManager.notify(NOTIFY_ID_TEMP_ALERT, notification);
|
||||||
|
LogUtils.d(TAG, "【通用临时通知】显示成功,通知ID:" + NOTIFY_ID_TEMP_ALERT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 场景4:自定义布局通知(灵活扩展,支持复杂样式)======================
|
||||||
|
/**
|
||||||
|
* 显示自定义布局通知(支持普通布局+大布局,通用所有场景,统一跳转MainActivity)
|
||||||
|
* @param contentView 普通自定义布局(必填)
|
||||||
|
* @param bigContentView 下拉大布局(可选)
|
||||||
|
*/
|
||||||
|
public void showCustomLayoutNotify(RemoteViews contentView, RemoteViews bigContentView) {
|
||||||
|
LogUtils.d(TAG, "【自定义布局通知】开始构建,布局ID:" + (contentView != null ? contentView.getLayoutId() : null));
|
||||||
|
if (contentView == null) {
|
||||||
|
LogUtils.e(TAG, "【自定义布局通知】构建失败:普通布局contentView为空");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 1. 构建固定跳转Intent(统一跳MainActivity)
|
||||||
|
PendingIntent pendingIntent = buildFixedPendingIntent();
|
||||||
|
// 2. 构建自定义布局通知
|
||||||
|
NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext, CHANNEL_ID_TEMP_ALERT)
|
||||||
|
.setSmallIcon(R.drawable.ic_launcher) // 必传,不可省略
|
||||||
|
.setContentIntent(pendingIntent)
|
||||||
|
.setContent(contentView)
|
||||||
|
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||||
|
.setAutoCancel(true);
|
||||||
|
// 添加大布局(可选)
|
||||||
|
if (bigContentView != null) {
|
||||||
|
builder.setCustomBigContentView(bigContentView);
|
||||||
|
LogUtils.d(TAG, "【自定义布局通知】已添加下拉大布局,布局ID:" + bigContentView.getLayoutId());
|
||||||
|
}
|
||||||
|
// 3. 发送通知
|
||||||
|
Notification notification = builder.build();
|
||||||
|
mNotificationManager.notify(NOTIFY_ID_CUSTOM_LAYOUT, notification);
|
||||||
|
LogUtils.d(TAG, "【自定义布局通知】显示成功,通知ID:" + NOTIFY_ID_CUSTOM_LAYOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 通知取消工具(支持精准取消/全取消)======================
|
||||||
|
/**
|
||||||
|
* 取消指定ID的通知(精准取消,灵活控制)
|
||||||
|
*/
|
||||||
|
public void cancelNotifyById(int notifyId) {
|
||||||
|
LogUtils.d(TAG, "【通知管理】开始取消通知,ID:" + notifyId);
|
||||||
|
mNotificationManager.cancel(notifyId);
|
||||||
|
LogUtils.d(TAG, "【通知管理】通知取消成功,ID:" + notifyId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消所有通知(谨慎使用,会清除所有场景的通知)
|
||||||
|
*/
|
||||||
|
public void cancelAllNotifies() {
|
||||||
|
LogUtils.d(TAG, "【通知管理】开始取消所有通知");
|
||||||
|
mNotificationManager.cancelAll();
|
||||||
|
LogUtils.d(TAG, "【通知管理】所有通知取消完成");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,247 +0,0 @@
|
|||||||
package cc.winboll.studio.powerbell.utils;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 参考:
|
|
||||||
* https://blog.csdn.net/qq_35507234/article/details/90676587
|
|
||||||
* https://blog.csdn.net/qq_16628781/article/details/51548324
|
|
||||||
*/
|
|
||||||
|
|
||||||
import android.app.Notification;
|
|
||||||
import android.app.NotificationChannel;
|
|
||||||
import android.app.NotificationManager;
|
|
||||||
import android.app.PendingIntent;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.graphics.BitmapFactory;
|
|
||||||
import android.graphics.Color;
|
|
||||||
import android.media.RingtoneManager;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.RemoteViews;
|
|
||||||
import androidx.annotation.RequiresApi;
|
|
||||||
import cc.winboll.studio.powerbell.MainActivity;
|
|
||||||
import cc.winboll.studio.powerbell.R;
|
|
||||||
import cc.winboll.studio.powerbell.model.NotificationMessage;
|
|
||||||
import cc.winboll.studio.powerbell.services.ControlCenterService;
|
|
||||||
|
|
||||||
public class NotificationUtils2 {
|
|
||||||
|
|
||||||
public static final String TAG = NotificationHelper.class.getSimpleName();
|
|
||||||
|
|
||||||
Context mContext;
|
|
||||||
NotificationManager mNotificationManager;
|
|
||||||
|
|
||||||
Notification mForegroundNotification;
|
|
||||||
PendingIntent mForegroundPendingIntent;
|
|
||||||
Notification mRemindNotification;
|
|
||||||
PendingIntent mRemindPendingIntent;
|
|
||||||
RemoteViews mrvServiceNotificationView;
|
|
||||||
RemoteViews mrvRemindNotificationView;
|
|
||||||
|
|
||||||
static enum NotificationType { MIN, MAX };
|
|
||||||
private static int _mnServiceNotificationID = 1;
|
|
||||||
private static int _mnRemindNotificationID = 2;
|
|
||||||
private static String _mszChannelIDService = "1";
|
|
||||||
private static String _mszChannelNameService = "Service";
|
|
||||||
private static String _mszChannelIDRemind = "2";
|
|
||||||
private static String _mszChannelNameRemind = "Remind";
|
|
||||||
|
|
||||||
// public NotificationUtils(Context context) {
|
|
||||||
// mContext = context;
|
|
||||||
// mNotificationManager = (NotificationManager) context.getSystemService(
|
|
||||||
// Context.NOTIFICATION_SERVICE);
|
|
||||||
// }
|
|
||||||
|
|
||||||
public NotificationUtils2(Context context) {
|
|
||||||
mContext = context;
|
|
||||||
mNotificationManager = context.getSystemService(NotificationManager.class);
|
|
||||||
//createNotificationChannels();
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
|
||||||
public void createNotificationChannels() {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
createServiceChannel();
|
|
||||||
createRemindChannel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
|
||||||
private void createServiceChannel() {
|
|
||||||
NotificationChannel channel = new NotificationChannel(
|
|
||||||
_mszChannelIDService,
|
|
||||||
_mszChannelNameService,
|
|
||||||
NotificationManager.IMPORTANCE_LOW
|
|
||||||
);
|
|
||||||
channel.setDescription("Background service updates");
|
|
||||||
channel.setSound(null, null);
|
|
||||||
channel.enableVibration(false);
|
|
||||||
mNotificationManager.createNotificationChannel(channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
|
||||||
private void createRemindChannel() {
|
|
||||||
NotificationChannel channel = new NotificationChannel(
|
|
||||||
_mszChannelIDRemind,
|
|
||||||
_mszChannelNameRemind,
|
|
||||||
NotificationManager.IMPORTANCE_HIGH
|
|
||||||
);
|
|
||||||
channel.setDescription("Critical reminders");
|
|
||||||
channel.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM), null);
|
|
||||||
channel.enableVibration(true);
|
|
||||||
channel.setVibrationPattern(new long[]{100, 200, 300, 400});
|
|
||||||
channel.setBypassDnd(true);
|
|
||||||
channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
|
|
||||||
mNotificationManager.createNotificationChannel(channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建并发送服务通知
|
|
||||||
//
|
|
||||||
public void createForegroundNotification(ControlCenterService service, NotificationMessage notificationMessage) {
|
|
||||||
//创建Notification,传入Context和channelId
|
|
||||||
Intent intent = new Intent();//这个intent会传给目标,可以使用getIntent来获取
|
|
||||||
intent.setPackage(service.getPackageName());
|
|
||||||
//LogUtils.d(TAG, "mService.getPackageName() : " + service.getPackageName());
|
|
||||||
intent.setClass(service, MainActivity.class);
|
|
||||||
//LogUtils.d(TAG, "MainActivity.class.getName() : " + MainActivity.class.getName());
|
|
||||||
//这里放一个count用来区分每一个通知
|
|
||||||
//intent.putExtra("intent", "intent--->" + count);//这里设置一个数据,带过去
|
|
||||||
|
|
||||||
//参数1:context 上下文对象
|
|
||||||
//参数2:发送者私有的请求码(Private request code for the sender)
|
|
||||||
//参数3:intent 意图对象
|
|
||||||
//参数4:必须为FLAG_ONE_SHOT,FLAG_NO_CREATE,FLAG_CANCEL_CURRENT,FLAG_UPDATE_CURRENT,中的一个
|
|
||||||
//mForegroundPendingIntent = PendingIntent.getActivity(mService, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
||||||
mForegroundPendingIntent = PendingIntent.getActivity(service,
|
|
||||||
1, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
|
|
||||||
} else {
|
|
||||||
mForegroundPendingIntent = PendingIntent.getActivity(service,
|
|
||||||
1, intent, PendingIntent.FLAG_IMMUTABLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
mForegroundNotification = new Notification.Builder(service, _mszChannelIDService)
|
|
||||||
.setAutoCancel(true)
|
|
||||||
.setContentTitle(notificationMessage.getTitle())
|
|
||||||
.setContentText(notificationMessage.getContent())
|
|
||||||
.setWhen(System.currentTimeMillis())
|
|
||||||
.setSmallIcon(R.drawable.ic_launcher)
|
|
||||||
//设置红色
|
|
||||||
.setColor(Color.parseColor("#F00606"))
|
|
||||||
.setLargeIcon(BitmapFactory.decodeResource(service.getResources(), R.drawable.ic_launcher))
|
|
||||||
.setContentIntent(mForegroundPendingIntent)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
setForegroundNotificationRemoteViews(service, notificationMessage);
|
|
||||||
service.startForeground(_mnServiceNotificationID, mForegroundNotification);
|
|
||||||
}
|
|
||||||
|
|
||||||
void initmrvRemindNotificationView(ControlCenterService service, NotificationMessage notificationMessage) {
|
|
||||||
mrvRemindNotificationView = new RemoteViews(service.getPackageName(), R.layout.view_remindnotification);
|
|
||||||
mrvRemindNotificationView.setTextViewText(R.id.viewremindnotificationTextView1, notificationMessage.getTitle());
|
|
||||||
String szRemindMSG = notificationMessage.getRemindMSG();
|
|
||||||
//LogUtils.d(TAG, "szRemindMSG : " + szRemindMSG);
|
|
||||||
//mrvRemindNotificationView.setTextViewText(R.id.remoteviewTextView2, szRemindMSG);
|
|
||||||
if (szRemindMSG != null) {
|
|
||||||
if (szRemindMSG.trim().equals("-")) {
|
|
||||||
//LogUtils.d(TAG, "-");
|
|
||||||
mrvRemindNotificationView.setViewVisibility(R.id.remoteviewCharge, View.GONE);
|
|
||||||
mrvRemindNotificationView.setViewVisibility(R.id.remoteviewUsege, View.VISIBLE);
|
|
||||||
} else if (szRemindMSG.trim().equals("+")) {
|
|
||||||
//LogUtils.d(TAG, "+");
|
|
||||||
mrvRemindNotificationView.setViewVisibility(R.id.remoteviewUsege, View.GONE);
|
|
||||||
mrvRemindNotificationView.setViewVisibility(R.id.remoteviewCharge, View.VISIBLE);
|
|
||||||
}
|
|
||||||
mrvRemindNotificationView.setImageViewResource(R.id.remoteviewImageView1, R.drawable.ic_launcher);
|
|
||||||
//给我remoteViews上的控件tv_content添加监听事件
|
|
||||||
//remoteViews.setOnClickPendingIntent(R.id.remoteviewLinearLayout1, pi);
|
|
||||||
//return mrvServiceNotificationView;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void initmrvServiceNotificationView(ControlCenterService service, NotificationMessage notificationMessage) {
|
|
||||||
mrvServiceNotificationView = new RemoteViews(service.getPackageName(), R.layout.view_servicenotification);
|
|
||||||
mrvServiceNotificationView.setTextViewText(R.id.remoteviewTextView1, notificationMessage.getTitle());
|
|
||||||
//String szRemindMSG = notificationMessage.getRemindMSG();
|
|
||||||
//mrvServiceNotificationView.setTextViewText(R.id.remoteviewTextView2, szRemindMSG);
|
|
||||||
//rvServiceNotificationView.setTextViewText(R.id.remoteviewTextView3, notificationMessage.getContent() + Integer.toString(nTest));
|
|
||||||
mrvServiceNotificationView.setTextViewText(R.id.remoteviewTextView3, notificationMessage.getContent());
|
|
||||||
mrvServiceNotificationView.setImageViewResource(R.id.remoteviewImageView1, R.drawable.ic_launcher);
|
|
||||||
//给我remoteViews上的控件tv_content添加监听事件
|
|
||||||
//remoteViews.setOnClickPendingIntent(R.id.remoteviewLinearLayout1, pi);
|
|
||||||
//return mrvServiceNotificationView;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setForegroundNotificationRemoteViews(ControlCenterService service, NotificationMessage notificationMessage) {
|
|
||||||
initmrvServiceNotificationView(service, notificationMessage);
|
|
||||||
mForegroundNotification.contentView = mrvServiceNotificationView;
|
|
||||||
mForegroundNotification.bigContentView = mrvServiceNotificationView;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setRemindNotificationRemoteViews(ControlCenterService service, NotificationMessage notificationMessage) {
|
|
||||||
initmrvRemindNotificationView(service, notificationMessage);
|
|
||||||
mRemindNotification.contentView = mrvRemindNotificationView;
|
|
||||||
mRemindNotification.bigContentView = mrvRemindNotificationView;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新服务通知
|
|
||||||
//
|
|
||||||
public void updateForegroundNotification(ControlCenterService service, NotificationMessage notificationMessage) {
|
|
||||||
setForegroundNotificationRemoteViews(service, notificationMessage);
|
|
||||||
mNotificationManager.notify(_mnServiceNotificationID, mForegroundNotification);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建并发送电量提醒通知
|
|
||||||
//
|
|
||||||
public void updateRemindNotification(ControlCenterService service, NotificationMessage notificationMessage) {
|
|
||||||
//LogUtils.d(TAG, "updateRemindNotification : " + notificationMessage.getRemindMSG());
|
|
||||||
setRemindNotificationRemoteViews(service, notificationMessage);
|
|
||||||
mNotificationManager.notify(_mnRemindNotificationID, mRemindNotification);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void createRemindNotification(ControlCenterService service, NotificationMessage notificationMessage) {
|
|
||||||
//LogUtils.d(TAG, "notificationMessage : " + notificationMessage.getRemindMSG());
|
|
||||||
//创建Notification,传入Context和channelId
|
|
||||||
Intent intent = new Intent();//这个intent会传给目标,可以使用getIntent来获取
|
|
||||||
intent.setPackage(service.getPackageName());
|
|
||||||
intent.setClass(service, MainActivity.class);
|
|
||||||
//这里放一个count用来区分每一个通知
|
|
||||||
//intent.putExtra("intent", "intent--->" + count);//这里设置一个数据,带过去
|
|
||||||
|
|
||||||
//参数1:context 上下文对象
|
|
||||||
//参数2:发送者私有的请求码(Private request code for the sender)
|
|
||||||
//参数3:intent 意图对象
|
|
||||||
//参数4:必须为FLAG_ONE_SHOT,FLAG_NO_CREATE,FLAG_CANCEL_CURRENT,FLAG_UPDATE_CURRENT,中的一个
|
|
||||||
//mRemindPendingIntent = PendingIntent.getActivity(mService, 1, intent, PendingIntent.FLAG_CANCEL_CURRENT);
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
||||||
mRemindPendingIntent = PendingIntent.getActivity(service,
|
|
||||||
1, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
|
|
||||||
} else {
|
|
||||||
mRemindPendingIntent = PendingIntent.getActivity(service,
|
|
||||||
1, intent, PendingIntent.FLAG_IMMUTABLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
mRemindNotification = new Notification.Builder(service, _mszChannelIDRemind)
|
|
||||||
.setAutoCancel(true)
|
|
||||||
.setContentTitle(notificationMessage.getTitle())
|
|
||||||
.setContentText(notificationMessage.getContent())
|
|
||||||
.setWhen(System.currentTimeMillis())
|
|
||||||
.setSmallIcon(R.drawable.ic_launcher)
|
|
||||||
//设置红色
|
|
||||||
.setColor(Color.parseColor("#F00606"))
|
|
||||||
.setLargeIcon(BitmapFactory.decodeResource(service.getResources(), R.drawable.ic_launcher))
|
|
||||||
.setContentIntent(mRemindPendingIntent)
|
|
||||||
.build();
|
|
||||||
setRemindNotificationRemoteViews(service, notificationMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void cancelRemindNotification(Context context){
|
|
||||||
// 获取 NotificationManager 实例
|
|
||||||
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
|
||||||
// 撤回指定 ID 的通知栏消息
|
|
||||||
notificationManager.cancel(_mnRemindNotificationID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,32 +1,35 @@
|
|||||||
package cc.winboll.studio.powerbell.utils;
|
package cc.winboll.studio.powerbell.utils;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.pm.PackageManager;
|
import android.app.AlertDialog;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.os.PowerManager;
|
||||||
import androidx.core.app.ActivityCompat;
|
import android.provider.Settings;
|
||||||
import androidx.core.content.ContextCompat;
|
|
||||||
|
|
||||||
import cc.winboll.studio.libappbase.LogUtils;
|
import cc.winboll.studio.libappbase.LogUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 权限申请工具类
|
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
|
||||||
* 适配 Android 13+ 媒体权限 & 低版本存储权限
|
* @Date 2025/12/14 03:05
|
||||||
* 兼容 SDK 版本低于 33 的编译环境
|
* @Describe 权限申请工具类(Java7兼容版)
|
||||||
|
* 适配 小米手机+API30,专注自启动权限、电池优化权限检查与申请
|
||||||
*/
|
*/
|
||||||
public class PermissionUtils {
|
public class PermissionUtils {
|
||||||
private static final String TAG = "PermissionUtils";
|
// ====================== 常量定义(统一管理,首屏可见)======================
|
||||||
// 存储权限请求码
|
public static final String TAG = "PermissionUtils";
|
||||||
public static final int REQUEST_STORAGE = 1000;
|
// 权限请求码(仅保留核心权限场景)
|
||||||
// 媒体图片权限请求码(Android 13+)
|
public static final int REQUEST_IGNORE_BATTERY_OPTIMIZATION = 1000; // 电池优化权限
|
||||||
public static final int REQUEST_READ_MEDIA_IMAGES = 1001;
|
public static final int REQUEST_AUTO_START = 1001; // 自启动权限(小米专属)
|
||||||
|
// SDK版本常量(适配API30,替代系统枚举)
|
||||||
|
private static final int SDK_VERSION_R = 30; // Android 11(API30)
|
||||||
|
// 小米手机自启动权限页面包名/类名(小米专属跳转路径)
|
||||||
|
private static final String XIAOMI_AUTO_START_PACKAGE = "com.miui.securitycenter";
|
||||||
|
private static final String XIAOMI_AUTO_START_CLASS = "com.miui.permcenter.autostart.AutoStartManagementActivity";
|
||||||
|
|
||||||
// 手动定义 Android 13+ 媒体图片权限常量(解决 SDK 低于 33 无法识别问题)
|
// ====================== 单例模式(Java7标准双重校验锁)======================
|
||||||
private static final String READ_MEDIA_IMAGES = "android.permission.READ_MEDIA_IMAGES";
|
|
||||||
// Android 13 对应的 SDK 版本号(替代 Build.VERSION_CODES.TIRAMISU)
|
|
||||||
private static final int SDK_VERSION_TIRAMISU = 33;
|
|
||||||
|
|
||||||
// 单例模式
|
|
||||||
private static volatile PermissionUtils sInstance;
|
private static volatile PermissionUtils sInstance;
|
||||||
|
|
||||||
private PermissionUtils() {}
|
private PermissionUtils() {}
|
||||||
@@ -36,99 +39,184 @@ public class PermissionUtils {
|
|||||||
synchronized (PermissionUtils.class) {
|
synchronized (PermissionUtils.class) {
|
||||||
if (sInstance == null) {
|
if (sInstance == null) {
|
||||||
sInstance = new PermissionUtils();
|
sInstance = new PermissionUtils();
|
||||||
|
LogUtils.d(TAG, "【单例初始化】PermissionUtils 实例创建成功");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sInstance;
|
return sInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ====================== 自启动权限(拆分检查+请求,小米专属)======================
|
||||||
/**
|
/**
|
||||||
* 检查并请求 存储权限(Android 12及以下)
|
* 检查是否拥有自启动权限(小米手机专属判断,API30适配)
|
||||||
|
* 注:小米自启动无系统API直接校验,通过「是否为小米机型」+「功能场景间接判断」,此处返回机型适配状态
|
||||||
|
* @param activity 上下文Activity(不可为null)
|
||||||
|
* @return true:小米机型(需手动开启权限);false:非小米机型(无需申请)
|
||||||
*/
|
*/
|
||||||
public boolean checkAndRequestStoragePermission(Activity activity) {
|
public boolean checkAutoStartPermission(Activity activity) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
if (activity == null) {
|
||||||
// Android 11+ 无需申请 READ_EXTERNAL_STORAGE,直接返回true
|
LogUtils.e(TAG, "【自启动权限-检查】失败:Activity为空");
|
||||||
return true;
|
return false;
|
||||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
||||||
String[] permissions = {
|
|
||||||
android.Manifest.permission.READ_EXTERNAL_STORAGE,
|
|
||||||
android.Manifest.permission.WRITE_EXTERNAL_STORAGE
|
|
||||||
};
|
|
||||||
if (ContextCompat.checkSelfPermission(activity, permissions[0]) != PackageManager.PERMISSION_GRANTED
|
|
||||||
|| ContextCompat.checkSelfPermission(activity, permissions[1]) != PackageManager.PERMISSION_GRANTED) {
|
|
||||||
ActivityCompat.requestPermissions(activity, permissions, REQUEST_STORAGE);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
LogUtils.d(TAG, "【自启动权限-检查】开始,设备品牌:" + Build.BRAND + ",系统版本:" + Build.VERSION.SDK_INT);
|
||||||
|
|
||||||
|
// 仅小米机型需要申请自启动权限,非小米直接返回false(无需处理)
|
||||||
|
boolean isXiaomi = Build.BRAND.toLowerCase().contains("xiaomi");
|
||||||
|
LogUtils.d(TAG, "【自启动权限-检查】结果:" + (isXiaomi ? "小米机型(需手动开启)" : "非小米机型(无需申请)"));
|
||||||
|
return isXiaomi;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查并请求 媒体图片权限(Android 13+)
|
* 请求自启动权限(小米手机专属,API30适配,跳转系统页面引导开启)
|
||||||
* 兼容 SDK 编译版本低于 33 的情况
|
* @param activity 申请权限的Activity(不可为null)
|
||||||
*/
|
*/
|
||||||
public boolean checkAndRequestMediaImagesPermission(Activity activity, int requestCode) {
|
public void requestAutoStartPermission(Activity activity) {
|
||||||
// 用数值 33 替代 Build.VERSION_CODES.TIRAMISU
|
if (activity == null) {
|
||||||
if (Build.VERSION.SDK_INT >= SDK_VERSION_TIRAMISU) {
|
LogUtils.e(TAG, "【自启动权限-请求】失败:Activity为空");
|
||||||
// 用手动定义的权限常量替代 android.Manifest.permission.READ_MEDIA_IMAGES
|
return;
|
||||||
if (ContextCompat.checkSelfPermission(activity, READ_MEDIA_IMAGES) != PackageManager.PERMISSION_GRANTED) {
|
|
||||||
ActivityCompat.requestPermissions(activity, new String[]{READ_MEDIA_IMAGES}, requestCode);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// 低版本已通过存储权限覆盖,直接返回true
|
// 先检查机型,非小米不执行请求
|
||||||
return true;
|
if (!checkAutoStartPermission(activity)) {
|
||||||
}
|
LogUtils.d(TAG, "【自启动权限-请求】非小米机型,无需发起请求");
|
||||||
|
return;
|
||||||
/**
|
|
||||||
* 权限请求结果处理
|
|
||||||
*/
|
|
||||||
public void handleStoragePermissionResult(Activity activity, int requestCode, String[] permissions, int[] grantResults) {
|
|
||||||
switch (requestCode) {
|
|
||||||
case REQUEST_STORAGE:
|
|
||||||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
|
||||||
LogUtils.d(TAG, "存储权限申请成功");
|
|
||||||
} else {
|
|
||||||
LogUtils.e(TAG, "存储权限申请失败");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case REQUEST_READ_MEDIA_IMAGES:
|
|
||||||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
|
||||||
LogUtils.d(TAG, "媒体图片权限申请成功");
|
|
||||||
} else {
|
|
||||||
LogUtils.e(TAG, "媒体图片权限申请失败");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LogUtils.d(TAG, "未知权限请求码:" + requestCode);
|
|
||||||
}
|
}
|
||||||
}
|
LogUtils.d(TAG, "【自启动权限-请求】开始处理,系统版本:" + Build.VERSION.SDK_INT);
|
||||||
|
|
||||||
/**
|
// API30+ 小米手机:优先精准跳转自启动管理页
|
||||||
* 检查是否有管理所有文件权限(Android 11+)
|
if (Build.VERSION.SDK_INT >= SDK_VERSION_R) {
|
||||||
*/
|
|
||||||
public boolean checkManageExternalStoragePermission(Activity activity) {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
|
||||||
return android.os.Environment.isExternalStorageManager();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 请求管理所有文件权限(Android 11+)
|
|
||||||
*/
|
|
||||||
public void requestManageExternalStoragePermission(Activity activity, int requestCode) {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
|
||||||
try {
|
try {
|
||||||
android.content.Intent intent = new android.content.Intent(
|
// 方案1:组件名精准跳转(成功率最高)
|
||||||
android.provider.Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION
|
Intent intent = new Intent();
|
||||||
);
|
intent.setComponent(new ComponentName(XIAOMI_AUTO_START_PACKAGE, XIAOMI_AUTO_START_CLASS));
|
||||||
intent.setData(android.net.Uri.parse("package:" + activity.getPackageName()));
|
activity.startActivityForResult(intent, REQUEST_AUTO_START);
|
||||||
activity.startActivityForResult(intent, requestCode);
|
LogUtils.d(TAG, "【自启动权限-请求】跳转小米自启动管理页(组件名跳转)");
|
||||||
} catch (Exception e) {
|
} catch (Exception e1) {
|
||||||
LogUtils.e(TAG, "请求管理文件权限异常:" + e.getMessage());
|
try {
|
||||||
|
// 方案2:Action备用跳转(兼容机型差异)
|
||||||
|
Intent intent = new Intent("miui.intent.action.OP_AUTO_START");
|
||||||
|
intent.setClassName(XIAOMI_AUTO_START_PACKAGE, XIAOMI_AUTO_START_CLASS);
|
||||||
|
activity.startActivityForResult(intent, REQUEST_AUTO_START);
|
||||||
|
LogUtils.d(TAG, "【自启动权限-请求】跳转小米自启动管理页(Action跳转)");
|
||||||
|
} catch (Exception e2) {
|
||||||
|
// 方案3:终极备用(跳转系统设置,引导手动操作)
|
||||||
|
Intent intent = new Intent(Settings.ACTION_SETTINGS);
|
||||||
|
activity.startActivityForResult(intent, REQUEST_AUTO_START);
|
||||||
|
LogUtils.w(TAG, "【自启动权限-请求】跳转系统设置页(引导手动开启)");
|
||||||
|
showAutoStartTipsDialog(activity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// API30以下小米手机:兼容低版本跳转逻辑
|
||||||
|
LogUtils.d(TAG, "【自启动权限-请求】API30以下小米机型,执行低版本跳转");
|
||||||
|
try {
|
||||||
|
Intent intent = new Intent(XIAOMI_AUTO_START_CLASS);
|
||||||
|
intent.setPackage(XIAOMI_AUTO_START_PACKAGE);
|
||||||
|
activity.startActivityForResult(intent, REQUEST_AUTO_START);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Intent intent = new Intent(Settings.ACTION_SETTINGS);
|
||||||
|
activity.startActivityForResult(intent, REQUEST_AUTO_START);
|
||||||
|
showAutoStartTipsDialog(activity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 电池优化权限(拆分检查+请求,通用所有机型)======================
|
||||||
|
/**
|
||||||
|
* 检查是否拥有「忽略电池优化」权限(API30适配,通用所有机型,精准返回权限状态)
|
||||||
|
* @param activity 上下文Activity(不可为null)
|
||||||
|
* @return true:已拥有(忽略优化);false:未拥有(需申请)
|
||||||
|
*/
|
||||||
|
public boolean checkIgnoreBatteryOptimizationPermission(Activity activity) {
|
||||||
|
if (activity == null) {
|
||||||
|
LogUtils.e(TAG, "【电池优化权限-检查】失败:Activity为空");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LogUtils.d(TAG, "【电池优化权限-检查】开始,系统版本:" + Build.VERSION.SDK_INT);
|
||||||
|
|
||||||
|
// API23以下无电池优化权限,直接视为已拥有
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
||||||
|
LogUtils.d(TAG, "【电池优化权限-检查】API23以下无此权限,视为已拥有");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// API23+ 精准校验权限状态
|
||||||
|
PowerManager powerManager = (PowerManager) activity.getSystemService(Activity.POWER_SERVICE);
|
||||||
|
if (powerManager == null) {
|
||||||
|
LogUtils.e(TAG, "【电池优化权限-检查】获取PowerManager失败,无法校验");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
boolean isIgnored = powerManager.isIgnoringBatteryOptimizations(activity.getPackageName());
|
||||||
|
LogUtils.d(TAG, "【电池优化权限-检查】结果:" + (isIgnored ? "已拥有(忽略优化)" : "未拥有(需申请)"));
|
||||||
|
return isIgnored;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求「忽略电池优化」权限(API30适配,通用所有机型,自动判断是否需要申请)
|
||||||
|
* @param activity 申请权限的Activity(不可为null)
|
||||||
|
*/
|
||||||
|
public void requestIgnoreBatteryOptimizationPermission(Activity activity) {
|
||||||
|
if (activity == null) {
|
||||||
|
LogUtils.e(TAG, "【电池优化权限-请求】失败:Activity为空");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 先检查权限,已拥有则直接返回
|
||||||
|
if (checkIgnoreBatteryOptimizationPermission(activity)) {
|
||||||
|
LogUtils.d(TAG, "【电池优化权限-请求】已拥有权限,无需发起申请");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LogUtils.w(TAG, "【电池优化权限-请求】未拥有权限,开始发起申请");
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 方案1:直接跳转权限申请页(用户一键同意,优先使用)
|
||||||
|
Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
|
||||||
|
intent.setData(Uri.parse("package:" + activity.getPackageName()));
|
||||||
|
activity.startActivityForResult(intent, REQUEST_IGNORE_BATTERY_OPTIMIZATION);
|
||||||
|
LogUtils.d(TAG, "【电池优化权限-请求】跳转系统权限申请页");
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 方案2:备用跳转(跳转优化管理列表,引导手动选择)
|
||||||
|
Intent intent = new Intent(Settings.ACTION_BATTERY_SAVER_SETTINGS);
|
||||||
|
activity.startActivityForResult(intent, REQUEST_IGNORE_BATTERY_OPTIMIZATION);
|
||||||
|
LogUtils.w(TAG, "【电池优化权限-请求】跳转优化管理页(引导手动开启)");
|
||||||
|
showBatteryOptTipsDialog(activity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====================== 辅助方法(提示弹窗+结果处理)======================
|
||||||
|
/**
|
||||||
|
* 显示自启动权限手动开启提示弹窗(小米机型跳转失败时使用)
|
||||||
|
*/
|
||||||
|
private void showAutoStartTipsDialog(final Activity activity) {
|
||||||
|
new AlertDialog.Builder(activity)
|
||||||
|
.setTitle("权限申请提示")
|
||||||
|
.setMessage("请手动开启自启动权限,否则应用后台功能可能异常:\n1. 进入安全中心 → 应用管理 → 自启动管理\n2. 找到本应用,开启「允许自启动」开关")
|
||||||
|
.setPositiveButton("知道了", new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
dialog.dismiss();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setCancelable(false)
|
||||||
|
.show();
|
||||||
|
LogUtils.d(TAG, "【自启动权限】显示手动开启提示弹窗");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示电池优化权限手动开启提示弹窗(跳转失败时使用)
|
||||||
|
*/
|
||||||
|
private void showBatteryOptTipsDialog(final Activity activity) {
|
||||||
|
new AlertDialog.Builder(activity)
|
||||||
|
.setTitle("权限申请提示")
|
||||||
|
.setMessage("请手动忽略电池优化,否则应用后台运行可能被限制:\n1. 进入设置 → 电池 → 电池优化\n2. 找到本应用,选择「不优化」")
|
||||||
|
.setPositiveButton("知道了", new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
dialog.dismiss();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setCancelable(false)
|
||||||
|
.show();
|
||||||
|
LogUtils.d(TAG, "【电池优化权限】显示手动开启提示弹窗");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package cc.winboll.studio.powerbell.utils;
|
package cc.winboll.studio.powerbell.utils;
|
||||||
|
|
||||||
import cc.winboll.studio.powerbell.model.BatteryInfoBean;
|
import cc.winboll.studio.powerbell.models.BatteryInfoBean;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public class StringUtils {
|
public class StringUtils {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
public class UriUtil {
|
public class UriUtils {
|
||||||
|
|
||||||
public static final String TAG = "UriUtil";
|
public static final String TAG = "UriUtil";
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ import android.widget.RelativeLayout;
|
|||||||
import cc.winboll.studio.libappbase.LogUtils;
|
import cc.winboll.studio.libappbase.LogUtils;
|
||||||
import cc.winboll.studio.libappbase.ToastUtils;
|
import cc.winboll.studio.libappbase.ToastUtils;
|
||||||
import cc.winboll.studio.powerbell.App;
|
import cc.winboll.studio.powerbell.App;
|
||||||
import cc.winboll.studio.powerbell.model.BackgroundBean;
|
import cc.winboll.studio.powerbell.models.BackgroundBean;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -20,8 +20,7 @@
|
|||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:background="#FF28C000">
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -32,7 +31,6 @@
|
|||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="#FF3243E2"
|
|
||||||
android:id="@+id/background_view">
|
android:id="@+id/background_view">
|
||||||
|
|
||||||
</cc.winboll.studio.powerbell.views.BackgroundView>
|
</cc.winboll.studio.powerbell.views.BackgroundView>
|
||||||
@@ -42,8 +40,7 @@
|
|||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="400dp"
|
android:layout_height="400dp">
|
||||||
android:background="#B92FABE6">
|
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|||||||
@@ -25,11 +25,11 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="center_vertical|center_horizontal">
|
android:gravity="center_vertical|center_horizontal">
|
||||||
|
|
||||||
<ImageView
|
<cc.winboll.studio.powerbell.views.BackgroundView
|
||||||
android:layout_width="wrap_content"
|
android:orientation="vertical"
|
||||||
android:layout_height="wrap_content"
|
android:layout_width="200dp"
|
||||||
android:scaleType="centerCrop"
|
android:layout_height="200dp"
|
||||||
android:id="@+id/dialogbackgroundpicturepreviewImageView1"/>
|
android:id="@+id/backgroundview"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user