diff --git a/.gitignore b/.gitignore index 93b01d7..b8589a9 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ local.properties *.jks *.keystore keystore.properties +/release \ No newline at end of file diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 132c690..a5829d5 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -24,6 +24,8 @@ + + + android:exported="true"> - + diff --git a/src/net/typeblog/lunatic/Manager/AnimationManager.java b/src/net/typeblog/lunatic/Manager/AnimationManager.java index 1b0c56b..d6a9ad9 100644 --- a/src/net/typeblog/lunatic/Manager/AnimationManager.java +++ b/src/net/typeblog/lunatic/Manager/AnimationManager.java @@ -122,6 +122,7 @@ public final class AnimationManager { public void playCharging() { StatusManager.setChargingLedsActive(true); submit(() -> { + final int num_leds = mLEDManager.getNumLEDs(); int solid_leds = 0; mLEDManager.enableAllLEDs(false); mLEDManager.setColor(0xffffff); @@ -131,17 +132,17 @@ public final class AnimationManager { while (check(Constants.SpotlightMode.CHARGING)) { int batteryLevel = getBatteryLevel(); if (oldBatteryLevel != batteryLevel) { - solid_leds = Integer.valueOf(batteryLevel / mLEDManager.getNumLEDs()); + solid_leds = (int) Math.floor(batteryLevel / 100.0d * num_leds); for (int i = 0; i < solid_leds; i++) { - mLEDManager.enableLED(i, true); + mLEDManager.enableLED(num_leds - i - 1, true); Thread.sleep(150); } oldBatteryLevel = batteryLevel; } if (100 - solid_leds * mLEDManager.getNumLEDs() > 0) { - mLEDManager.enableLED(solid_leds, true); + mLEDManager.enableLED(num_leds - solid_leds - 1, true); Thread.sleep(500); - mLEDManager.enableLED(solid_leds, false); + mLEDManager.enableLED(num_leds - solid_leds - 1, false); Thread.sleep(500); } } @@ -214,6 +215,8 @@ public final class AnimationManager { } catch (InterruptedException e) { mLEDManager.enableAllLEDs(false); } + + stopNotifications(); }); } @@ -228,6 +231,7 @@ public final class AnimationManager { submit(() -> { if (check(Constants.SpotlightMode.FLASHLIGHT)) { + mLEDManager.setColor(0xffffff); mLEDManager.setBrightness((int) (Constants.BRIGHTNESS * 100)); mLEDManager.enableAllLEDs(true); } diff --git a/src/net/typeblog/lunatic/Services/NotificationService.java b/src/net/typeblog/lunatic/Services/NotificationService.java index 2260f93..d0829f9 100644 --- a/src/net/typeblog/lunatic/Services/NotificationService.java +++ b/src/net/typeblog/lunatic/Services/NotificationService.java @@ -39,7 +39,6 @@ public class NotificationService extends NotificationListenerService { private static final String TAG = "SpotlightNotification"; private static final boolean DEBUG = true; - private ArrayList mNotifications = new ArrayList<>(); private AnimationManager mAnimationManager; @Override @@ -87,19 +86,7 @@ public class NotificationService extends NotificationListenerService { && !Arrays.asList(Constants.APPSTOIGNORE).contains(packageName) && !Arrays.asList(Constants.NOTIFSTOIGNORE).contains(packageName + ":" + packageChannelID) && (packageImportance >= NotificationManager.IMPORTANCE_DEFAULT || packageImportance == -1)) { - mNotifications.add(sbn.getId()); mAnimationManager.playNotifications(); } } - - @Override - public void onNotificationRemoved(StatusBarNotification sbn){ - if (DEBUG) Log.d(TAG, "onNotificationRemoved: package:" + sbn.getPackageName() + " | channel id: " + sbn.getNotification().getChannelId() + " | id: " + sbn.getId()); - if (mNotifications.contains(sbn.getId())) { - mNotifications.remove((Integer) sbn.getId()); - } - if (mNotifications.isEmpty()) { - mAnimationManager.stopNotifications(); - } - } } diff --git a/src/net/typeblog/lunatic/Settings/SettingsFragment.java b/src/net/typeblog/lunatic/Settings/SettingsFragment.java index 1fa3bea..a36deda 100644 --- a/src/net/typeblog/lunatic/Settings/SettingsFragment.java +++ b/src/net/typeblog/lunatic/Settings/SettingsFragment.java @@ -105,7 +105,8 @@ public class SettingsFragment extends PreferenceFragment implements OnPreference final String preferenceKey = preference.getKey(); if (preferenceKey.equals(Constants.SPOTLIGHT_NOTIFS_ENABLE)) { - SettingsManager.setSpotlightNotifsEnabled(getActivity(), true); + mNotifsPreference.setChecked(SettingsManager.isSpotlightNotifsEnabled(getActivity())); + return false; } if (preferenceKey.equals(Constants.SPOTLIGHT_BRIGHTNESS)) { diff --git a/src/net/typeblog/lunatic/Utils/ServiceUtils.java b/src/net/typeblog/lunatic/Utils/ServiceUtils.java index ee332aa..2231664 100644 --- a/src/net/typeblog/lunatic/Utils/ServiceUtils.java +++ b/src/net/typeblog/lunatic/Utils/ServiceUtils.java @@ -18,8 +18,12 @@ package net.typeblog.lunatic.Utils; +import android.app.NotificationManager; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.os.PowerExemptionManager; +import android.os.UserHandle; import android.util.Log; import net.typeblog.lunatic.Constants.Constants; @@ -31,62 +35,101 @@ import net.typeblog.lunatic.Services.FlashlightService; import net.typeblog.lunatic.Services.MusicService; import net.typeblog.lunatic.Services.NotificationService; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + public final class ServiceUtils { private static final String TAG = "SpotlightServiceUtils"; private static final boolean DEBUG = true; + // Use reflection hack because Android Studio does not use our overridden framework.jar by default + private static void startServiceAsCurrentUser(Context context, Intent intent) { + try { + final Field currentField = UserHandle.class.getField("CURRENT"); + UserHandle current = (UserHandle) currentField.get(null); + final Method startServiceAsUser = Context.class.getMethod("startServiceAsUser", Intent.class, UserHandle.class); + startServiceAsUser.invoke(context, intent, current); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static void stopServiceAsCurrentUser(Context context, Intent intent) { + try { + final Field currentField = UserHandle.class.getField("CURRENT"); + UserHandle current = (UserHandle) currentField.get(null); + final Method stopServiceAsUser = Context.class.getMethod("stopServiceAsUser", Intent.class, UserHandle.class); + stopServiceAsUser.invoke(context, intent, current); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + public static void startCallReceiverService(Context context) { if (DEBUG) Log.d(TAG, "Starting Spotlight call receiver service"); - context.startService(new Intent(context, CallReceiverService.class)); + startServiceAsCurrentUser(context, new Intent(context, CallReceiverService.class)); } protected static void stopCallReceiverService(Context context) { if (DEBUG) Log.d(TAG, "Stopping Spotlight call receiver service"); - context.stopService(new Intent(context, CallReceiverService.class)); + stopServiceAsCurrentUser(context, new Intent(context, CallReceiverService.class)); } public static void startChargingService(Context context) { if (DEBUG) Log.d(TAG, "Starting Spotlight charging service"); - context.startService(new Intent(context, ChargingService.class)); + startServiceAsCurrentUser(context, new Intent(context, ChargingService.class)); } protected static void stopChargingService(Context context) { if (DEBUG) Log.d(TAG, "Stopping Spotlight charging service"); - context.stopService(new Intent(context, ChargingService.class)); + stopServiceAsCurrentUser(context, new Intent(context, ChargingService.class)); } public static void startNotificationService(Context context) { if (DEBUG) Log.d(TAG, "Starting Spotlight notifs service"); - context.startService(new Intent(context, NotificationService.class)); + startServiceAsCurrentUser(context, new Intent(context, NotificationService.class)); } protected static void stopNotificationService(Context context) { if (DEBUG) Log.d(TAG, "Stopping Spotlight notifs service"); - context.stopService(new Intent(context, NotificationService.class)); + stopServiceAsCurrentUser(context, new Intent(context, NotificationService.class)); } public static void startFlashlightService(Context context) { if (DEBUG) Log.d(TAG, "Starting Spotlight flashlight service"); - context.startService(new Intent(context, FlashlightService.class)); + startServiceAsCurrentUser(context, new Intent(context, FlashlightService.class)); } protected static void stopFlashlightService(Context context) { if (DEBUG) Log.d(TAG, "Stopping Spotlight flashlight service"); - context.stopService(new Intent(context, FlashlightService.class)); + stopServiceAsCurrentUser(context, new Intent(context, FlashlightService.class)); } public static void startMusicService(Context context) { if (DEBUG) Log.d(TAG, "Starting Spotlight Music service"); - context.startService(new Intent(context, MusicService.class)); + startServiceAsCurrentUser(context, new Intent(context, MusicService.class)); } protected static void stopMusicService(Context context) { if (DEBUG) Log.d(TAG, "Stopping Spotlight Music service"); - context.stopService(new Intent(context, MusicService.class)); + stopServiceAsCurrentUser(context, new Intent(context, MusicService.class)); } public static void checkSpotlightService(Context context) { + PowerExemptionManager pem = context.getSystemService(PowerExemptionManager.class); + pem.addToPermanentAllowList("net.typeblog.lunatic"); + + // Self-grant notification access because why not :) + NotificationManager nm = context.getSystemService(NotificationManager.class); + try { + Method setNotificationListenerAccessGranted = NotificationManager.class.getMethod("setNotificationListenerAccessGranted", + ComponentName.class, boolean.class, boolean.class); + setNotificationListenerAccessGranted.invoke(nm, new ComponentName(context, NotificationService.class), true, true); + } catch (Exception e) { + throw new RuntimeException(e); + } + AnimationManager animationManager = new AnimationManager(context); if (SettingsManager.isSpotlightEnabled(context)) {