diff --git a/powerbell/build.properties b/powerbell/build.properties index 005367c..cb30cf7 100644 --- a/powerbell/build.properties +++ b/powerbell/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Thu Jan 02 11:13:45 HKT 2025 +#Fri Mar 21 21:51:15 GMT 2025 stageCount=6 libraryProject= baseVersion=4.0 publishVersion=4.0.5 -buildCount=0 +buildCount=13 baseBetaVersion=4.0.6 diff --git a/powerbell/src/main/AndroidManifest.xml b/powerbell/src/main/AndroidManifest.xml index b7d17be..6c9175e 100644 --- a/powerbell/src/main/AndroidManifest.xml +++ b/powerbell/src/main/AndroidManifest.xml @@ -2,10 +2,9 @@ - - - - + + + @@ -22,6 +21,23 @@ + + + + + + + + + + + + + + + + + + android:launchMode="singleTask" + android:exported="true"> diff --git a/powerbell/src/main/java/cc/winboll/studio/powerbell/MainActivity.java b/powerbell/src/main/java/cc/winboll/studio/powerbell/MainActivity.java index c2a5eb6..e8c75fd 100644 --- a/powerbell/src/main/java/cc/winboll/studio/powerbell/MainActivity.java +++ b/powerbell/src/main/java/cc/winboll/studio/powerbell/MainActivity.java @@ -17,7 +17,7 @@ import cc.winboll.studio.powerbell.activities.AboutActivity; import cc.winboll.studio.powerbell.activities.BackgroundPictureActivity; import cc.winboll.studio.powerbell.activities.ClearRecordActivity; import cc.winboll.studio.powerbell.fragments.MainViewFragment; -import cc.winboll.studio.powerbell.utils.NotificationUtils; +import cc.winboll.studio.powerbell.utils.NotificationHelper; import cc.winboll.studio.shared.log.LogUtils; import cc.winboll.studio.shared.log.LogView; @@ -64,8 +64,10 @@ public class MainActivity extends Activity { } showFragment(mMainViewFragment); - NotificationUtils notificationUtils = new NotificationUtils(this); - notificationUtils.createNotificationChannel(); +// NotificationHelper notificationUtils = new NotificationHelper(this); +// notificationUtils.createNotificationChannels(); + + } void showFragment(Fragment fragment) { @@ -113,7 +115,7 @@ public class MainActivity extends Activity { protected void onResume() { super.onResume(); // 回到窗口自动取消提醒消息 - NotificationUtils.cancelRemindNotification(this); + //NotificationHelper.cancelRemindNotification(this); reloadBackground(); } diff --git a/powerbell/src/main/java/cc/winboll/studio/powerbell/receivers/GlobalApplicationReceiver.java b/powerbell/src/main/java/cc/winboll/studio/powerbell/receivers/GlobalApplicationReceiver.java index 3d7dde3..4eb3ffe 100644 --- a/powerbell/src/main/java/cc/winboll/studio/powerbell/receivers/GlobalApplicationReceiver.java +++ b/powerbell/src/main/java/cc/winboll/studio/powerbell/receivers/GlobalApplicationReceiver.java @@ -8,7 +8,7 @@ import cc.winboll.studio.powerbell.GlobalApplication; import cc.winboll.studio.powerbell.fragments.MainViewFragment; import cc.winboll.studio.powerbell.utils.AppConfigUtils; import cc.winboll.studio.powerbell.utils.BatteryUtils; -import cc.winboll.studio.powerbell.utils.NotificationUtils; +import cc.winboll.studio.powerbell.utils.NotificationHelper; public class GlobalApplicationReceiver extends BroadcastReceiver { @@ -45,7 +45,7 @@ public class GlobalApplicationReceiver extends BroadcastReceiver { // 新电池状态标志某一个有变化就更新显示信息 if (_mIsCharging != isCharging || _mnTheQuantityOfElectricityOld != nTheQuantityOfElectricity) { // 电池状态改变先取消旧的提醒消息 - NotificationUtils.cancelRemindNotification(context); + //NotificationHelper.cancelRemindNotification(context); GlobalApplication.getAppCacheUtils(context).addChangingTime(nTheQuantityOfElectricity); MainViewFragment.sendMsgCurrentValueBattery(nTheQuantityOfElectricity); diff --git a/powerbell/src/main/java/cc/winboll/studio/powerbell/services/ControlCenterService.java b/powerbell/src/main/java/cc/winboll/studio/powerbell/services/ControlCenterService.java index 20cc497..2d1b7aa 100644 --- a/powerbell/src/main/java/cc/winboll/studio/powerbell/services/ControlCenterService.java +++ b/powerbell/src/main/java/cc/winboll/studio/powerbell/services/ControlCenterService.java @@ -8,14 +8,17 @@ package cc.winboll.studio.powerbell.services; * Android Service之onStartCommand方法研究 * https://blog.csdn.net/cyp331203/article/details/38920491 */ -import cc.winboll.studio.powerbell.R; +import android.app.Notification; import android.app.Service; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.IBinder; +import android.widget.RemoteViews; import cc.winboll.studio.powerbell.GlobalApplication; +import cc.winboll.studio.powerbell.MainActivity; +import cc.winboll.studio.powerbell.R; import cc.winboll.studio.powerbell.beans.AppConfigBean; import cc.winboll.studio.powerbell.beans.NotificationMessage; import cc.winboll.studio.powerbell.handlers.ControlCenterServiceHandler; @@ -24,11 +27,12 @@ import cc.winboll.studio.powerbell.services.AssistantService; import cc.winboll.studio.powerbell.threads.RemindThread; import cc.winboll.studio.powerbell.utils.AppCacheUtils; import cc.winboll.studio.powerbell.utils.AppConfigUtils; -import cc.winboll.studio.powerbell.utils.NotificationUtils; +import cc.winboll.studio.powerbell.utils.NotificationHelper; import cc.winboll.studio.powerbell.utils.ServiceUtils; import cc.winboll.studio.powerbell.utils.StringUtils; import cc.winboll.studio.shared.log.LogUtils; import com.hjq.toast.ToastUtils; +import android.graphics.Color; public class ControlCenterService extends Service { @@ -43,7 +47,8 @@ public class ControlCenterService extends Service { AppConfigUtils mAppConfigUtils; AppCacheUtils mAppCacheUtils; // 前台服务通知工具 - NotificationUtils mNotificationUtils; + NotificationHelper mNotificationHelper; + Notification notification; RemindThread mRemindThread; ControlCenterServiceHandler mControlCenterServiceHandler; MyServiceConnection mMyServiceConnection; @@ -66,7 +71,9 @@ public class ControlCenterService extends Service { isServiceRunning = false; mAppConfigUtils = GlobalApplication.getAppConfigUtils(this); mAppCacheUtils = GlobalApplication.getAppCacheUtils(this); - mNotificationUtils = new NotificationUtils(ControlCenterService.this); + mNotificationHelper = new NotificationHelper(ControlCenterService.this); + + if (mMyServiceConnection == null) { mMyServiceConnection = new MyServiceConnection(); } @@ -92,10 +99,16 @@ public class ControlCenterService extends Service { // 唤醒守护进程 wakeupAndBindAssistant(); // 显示前台通知栏 - NotificationMessage notificationMessage=createNotificationMessage(); - //Toast.makeText(getApplication(), "", Toast.LENGTH_SHORT).show(); - mNotificationUtils.createForegroundNotification(this, notificationMessage); - mNotificationUtils.createRemindNotification(this, notificationMessage); + // 在Service中 + NotificationHelper helper = new NotificationHelper(this); + Intent intent = new Intent(this, MainActivity.class); + notification = helper.showForegroundNotification(intent, getString(R.string.app_name), "Service Running, Click to open app"); + startForeground(NotificationHelper.FOREGROUND_NOTIFICATION_ID, notification); + +// NotificationMessage notificationMessage=createNotificationMessage(); +// //Toast.makeText(getApplication(), "", Toast.LENGTH_SHORT).show(); +// mNotificationUtils.createForegroundNotification(this, notificationMessage); +// mNotificationUtils.createRemindNotification(this, notificationMessage); if (mControlCenterServiceReceiver == null) { // 注册广播接收器 @@ -126,19 +139,19 @@ public class ControlCenterService extends Service { // 更新前台通知 // public void updateServiceNotification() { - mNotificationUtils.updateForegroundNotification(ControlCenterService.this, createNotificationMessage()); + //mNotificationUtils.updateForegroundNotification(ControlCenterService.this, createNotificationMessage()); } // 更新前台通知 // public void updateServiceNotification(NotificationMessage notificationMessage) { - mNotificationUtils.updateForegroundNotification(ControlCenterService.this, notificationMessage); + //mNotificationUtils.updateForegroundNotification(ControlCenterService.this, notificationMessage); } // 更新前台通知 // public void updateRemindNotification(NotificationMessage notificationMessage) { - mNotificationUtils.updateRemindNotification(ControlCenterService.this, notificationMessage); + //mNotificationUtils.updateRemindNotification(ControlCenterService.this, notificationMessage); } // 唤醒和绑定守护进程 @@ -234,10 +247,32 @@ public class ControlCenterService extends Service { } public void appenRemindMSG(String szRemindMSG) { - NotificationMessage notificationMessage = createNotificationMessage(); - notificationMessage.setRemindMSG(szRemindMSG); - //LogUtils.d(TAG, "notificationMessage : " + notificationMessage.getRemindMSG()); - updateRemindNotification(notificationMessage); + String msg = ""; + for (int i = 0; i < 20; i++) { + msg += szRemindMSG; + } + NotificationHelper helper = new NotificationHelper(ControlCenterService.this); + Intent intent = new Intent(ControlCenterService.this, MainActivity.class); + helper.showTemporaryNotification(intent, getString(R.string.app_name), msg); + + + +// NotificationMessage notificationMessage = createNotificationMessage(); +// notificationMessage.setRemindMSG(szRemindMSG); +// //LogUtils.d(TAG, "notificationMessage : " + notificationMessage.getRemindMSG()); +// updateRemindNotification(notificationMessage); + } + + // 设置颜色背景 + public static RemoteViews setLinearLayoutColor(RemoteViews remoteViews, int viewId, int color) { + remoteViews.setInt(viewId, "setBackgroundColor", color); + return remoteViews; + } + + // 设置Drawable背景 + public static RemoteViews setLinearLayoutDrawable(RemoteViews remoteViews, int viewId, int drawableRes) { + remoteViews.setInt(viewId, "setBackgroundResource", drawableRes); + return remoteViews; } // diff --git a/powerbell/src/main/java/cc/winboll/studio/powerbell/utils/AppConfigUtils.java b/powerbell/src/main/java/cc/winboll/studio/powerbell/utils/AppConfigUtils.java index e1c2be0..4a21202 100644 --- a/powerbell/src/main/java/cc/winboll/studio/powerbell/utils/AppConfigUtils.java +++ b/powerbell/src/main/java/cc/winboll/studio/powerbell/utils/AppConfigUtils.java @@ -193,7 +193,7 @@ public class AppConfigUtils { // void saveConfigData() { // 更新配置先取消一下旧的的提醒消息 - NotificationUtils.cancelRemindNotification(mContext); + //NotificationHelper.cancelRemindNotification(mContext); AppConfigBean.saveBean(mContext, mAppConfigBean); // 通知活动窗口和服务配置已更新 diff --git a/powerbell/src/main/java/cc/winboll/studio/powerbell/utils/NotificationHelper.java b/powerbell/src/main/java/cc/winboll/studio/powerbell/utils/NotificationHelper.java new file mode 100644 index 0000000..cc62c37 --- /dev/null +++ b/powerbell/src/main/java/cc/winboll/studio/powerbell/utils/NotificationHelper.java @@ -0,0 +1,150 @@ +package cc.winboll.studio.powerbell.utils; + +/** + * @Author ZhanGSKen@AliYun.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) + .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 + ); + } +} + diff --git a/powerbell/src/main/java/cc/winboll/studio/powerbell/utils/NotificationUtils.java b/powerbell/src/main/java/cc/winboll/studio/powerbell/utils/NotificationUtils2.java similarity index 83% rename from powerbell/src/main/java/cc/winboll/studio/powerbell/utils/NotificationUtils.java rename to powerbell/src/main/java/cc/winboll/studio/powerbell/utils/NotificationUtils2.java index 5bcb692..a2fe111 100644 --- a/powerbell/src/main/java/cc/winboll/studio/powerbell/utils/NotificationUtils.java +++ b/powerbell/src/main/java/cc/winboll/studio/powerbell/utils/NotificationUtils2.java @@ -18,14 +18,15 @@ 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.beans.NotificationMessage; import cc.winboll.studio.powerbell.services.ControlCenterService; -public class NotificationUtils { +public class NotificationUtils2 { - public static final String TAG = NotificationUtils.class.getSimpleName(); + public static final String TAG = NotificationHelper.class.getSimpleName(); Context mContext; NotificationManager mNotificationManager; @@ -45,19 +46,53 @@ public class NotificationUtils { private static String _mszChannelIDRemind = "2"; private static String _mszChannelNameRemind = "Remind"; - public NotificationUtils(Context context) { +// public NotificationUtils(Context context) { +// mContext = context; +// mNotificationManager = (NotificationManager) context.getSystemService( +// Context.NOTIFICATION_SERVICE); +// } + + public NotificationUtils2(Context context) { mContext = context; - mNotificationManager = (NotificationManager) context.getSystemService( - Context.NOTIFICATION_SERVICE); + mNotificationManager = context.getSystemService(NotificationManager.class); + //createNotificationChannels(); } - public void createNotificationChannel() { - NotificationChannel channel1 = new NotificationChannel(_mszChannelIDService, _mszChannelNameService, NotificationManager.IMPORTANCE_DEFAULT); - channel1.setSound(null, null); - mNotificationManager.createNotificationChannel(channel1); - NotificationChannel channel2 = new NotificationChannel(_mszChannelIDRemind, _mszChannelNameRemind, NotificationManager.IMPORTANCE_HIGH); - channel2.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE), Notification.AUDIO_ATTRIBUTES_DEFAULT); - mNotificationManager.createNotificationChannel(channel2); + @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); } // 创建并发送服务通知 diff --git a/powerbell/src/main/res/layout/custom_notification.xml b/powerbell/src/main/res/layout/custom_notification.xml new file mode 100644 index 0000000..53ddf4b --- /dev/null +++ b/powerbell/src/main/res/layout/custom_notification.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/powerbell/src/main/res/layout/custom_notification_expanded.xml b/powerbell/src/main/res/layout/custom_notification_expanded.xml new file mode 100644 index 0000000..b93059b --- /dev/null +++ b/powerbell/src/main/res/layout/custom_notification_expanded.xml @@ -0,0 +1,17 @@ + + + + + + +