This commit is contained in:
JerryXiao 2023-08-18 12:24:07 +08:00
parent f0cd85370f
commit 183f98ac47
Signed by: Jerry
GPG key ID: 22618F758B5BE2E5
11 changed files with 252 additions and 26 deletions

View file

@ -36,6 +36,7 @@ dependencies {
implementation 'androidx.appcompat:appcompat:1.4.1' implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0' implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.core:core-ktx:1.10.1' implementation 'androidx.core:core-ktx:1.10.1'
implementation 'androidx.preference:preference:1.2.0'
testImplementation 'junit:junit:4.13.2' testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'

View file

@ -3,6 +3,7 @@
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application <application
android:allowBackup="true" android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules" android:dataExtractionRules="@xml/data_extraction_rules"
@ -13,18 +14,27 @@
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.EasterScrSaver" android:theme="@style/Theme.EasterScrSaver"
tools:targetApi="32"> tools:targetApi="32">
<activity
android:name=".SettingsActivity"
android:exported="false"
android:label="@string/title_activity_settings" />
<service <service
android:name=".EasterDream" android:name=".EasterDream"
android:exported="true" android:exported="true"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:permission="android.permission.BIND_DREAM_SERVICE"> android:permission="android.permission.BIND_DREAM_SERVICE">
<intent-filter>
<action android:name="android.service.dreams.DreamService" />
<intent-filter> <category android:name="android.intent.category.DEFAULT" />
<action android:name="android.service.dreams.DreamService" /> </intent-filter>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter> <meta-data
</service> android:name="android.service.dream"
android:resource="@xml/easterdream" />
</service>
</application> </application>
</manifest> </manifest>

View file

@ -4,12 +4,13 @@ import static android.graphics.PixelFormat.TRANSLUCENT;
import android.animation.Animator; import android.animation.Animator;
import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorListenerAdapter;
import android.annotation.SuppressLint;
import android.app.WallpaperManager; import android.app.WallpaperManager;
import android.content.SharedPreferences;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.ColorFilter; import android.graphics.ColorFilter;
import android.graphics.Paint; import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable; import android.graphics.drawable.LayerDrawable;
@ -27,12 +28,17 @@ import android.widget.ImageView;
import androidx.annotation.ChecksSdkIntAtLeast; import androidx.annotation.ChecksSdkIntAtLeast;
import androidx.core.app.ActivityCompat; import androidx.core.app.ActivityCompat;
import androidx.preference.PreferenceManager;
import java.util.ArrayList;
import java.util.Random;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
public class EasterDream extends DreamService { public class EasterDream extends DreamService {
private static String TAG = "easter_daydream"; private static String TAG = "EasterDream";
private SharedPreferences prefs;
private Drawable wallPaperDrawable = null; private Drawable wallPaperDrawable = null;
private FrameLayout last = null; private FrameLayout last = null;
private boolean enabled = false; private boolean enabled = false;
@ -101,7 +107,9 @@ public class EasterDream extends DreamService {
@Override @Override
public void onAttachedToWindow() { public void onAttachedToWindow() {
super.onAttachedToWindow(); super.onAttachedToWindow();
this.prefs = PreferenceManager.getDefaultSharedPreferences(this);
setScreenBright(!this.prefs.getBoolean("dim_screen", false));
// Exit dream upon user touch // Exit dream upon user touch
setInteractive(false); setInteractive(false);
// Hide system UI // Hide system UI
@ -119,7 +127,7 @@ public class EasterDream extends DreamService {
refresh(); refresh();
} }
private static final String[][] EMOJI_SETS = { protected static final String[][] EMOJI_SETS = {
{"🍇", "🍈", "🍉", "🍊", "🍋", "🍌", "🍍", "🥭", "🍎", "🍏", "🍐", "🍑", {"🍇", "🍈", "🍉", "🍊", "🍋", "🍌", "🍍", "🥭", "🍎", "🍏", "🍐", "🍑",
"🍒", "🍓", "🫐", "🥝"}, "🍒", "🍓", "🫐", "🥝"},
{"😺", "😸", "😹", "😻", "😼", "😽", "🙀", "😿", "😾"}, {"😺", "😸", "😹", "😻", "😼", "😽", "🙀", "😿", "😾"},
@ -245,20 +253,37 @@ class BubblesDrawable extends Drawable {
//randomize(); //randomize();
//chooseEmojiSet(); //chooseEmojiSet();
} }
}, 10000L); }, Integer.parseInt(EasterDream.this.prefs.getString("switch_time", "10")) * 1000L);
} }
public void chooseEmojiSet() { public void chooseEmojiSet() {
if (Math.random() < 0.8) { ArrayList<Integer> probList = new ArrayList<>();
if (Math.random() < 0.4) { int probSum = 0;
mEmojiSet = 0; for (int i = 0; i < EMOJI_SETS.length; i++) {
} @SuppressLint("DefaultLocale")
else { int p = Integer.parseInt(EasterDream.this.prefs.getString(String.format("prob_%d", i), "5"));
mEmojiSet = 13; probSum += p;
} probList.add(probSum);
//Log.d(TAG, String.format("probList %d %d", i, probSum));
}
//Log.d(TAG, String.format("probSum %d", probSum));
if (probSum <= 0) {
mEmojiSet = (int) (Math.random() * EMOJI_SETS.length);
} }
else { else {
mEmojiSet = (int) (Math.random() * EMOJI_SETS.length); mEmojiSet = -1;
int r = (new Random()).nextInt(probSum);
for (int i = 0; i < EMOJI_SETS.length; i++) {
if (r < probList.get(i)) {
mEmojiSet = i;
break;
}
}
//Log.d(TAG, String.format("probRand %d", r));
if (mEmojiSet < 0) {
Log.e(TAG, String.format("unexpected mEmojiSet %d", mEmojiSet));
mEmojiSet = (int) (Math.random() * EMOJI_SETS.length);
}
} }
final String[] emojiSet = EMOJI_SETS[mEmojiSet]; final String[] emojiSet = EMOJI_SETS[mEmojiSet];
Log.i(TAG, "chooseEmojiSet: " + mEmojiSet); Log.i(TAG, "chooseEmojiSet: " + mEmojiSet);

View file

@ -0,0 +1,102 @@
package cc.jerryxiao.easterscrsaver;
import android.annotation.SuppressLint;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.preference.ListPreference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceFragmentCompat;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class SettingsActivity extends AppCompatActivity {
private static String TAG = "EasterDream";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.settings_activity);
if (savedInstanceState == null) {
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.settings, new SettingsFragment())
.commit();
}
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
Map<String, String> permissionsToRequest = new HashMap<>();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
permissionsToRequest.putAll(Map.of("android.permission.READ_EXTERNAL_STORAGE",
getString(R.string.permission_denied_read_external_storage)));
Iterator<Map.Entry<String, String>> it = permissionsToRequest.entrySet().iterator();
if (it.hasNext()) {
if (checkSelfPermission(it.next().getKey()) == PackageManager.PERMISSION_GRANTED) {
it.remove();
}
}
}
if (!permissionsToRequest.isEmpty()) {
Log.d(TAG, String.format("requesting permissions %s", String.join(" + ", permissionsToRequest.keySet().toArray(new String[0]))));
ActivityResultLauncher<String[]> permissionReq = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), (result) -> {
for (var res : result.entrySet()) {
var perm = res.getKey();
var granted = res.getValue();
if (!granted) {
Log.d(TAG, String.format("permission denied: %s", perm));
(new AlertDialog.Builder(this))
.setTitle(getText(R.string.error_title))
.setMessage(permissionsToRequest.get(perm))
.setCancelable(false)
.setPositiveButton(getString(R.string.button_ok), (dialog, id) -> {
})
.create()
.show();
}
}
});
permissionReq.launch(permissionsToRequest.keySet().toArray(new String[0]));
}
}
@Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
public static class SettingsFragment extends PreferenceFragmentCompat {
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.preferences, rootKey);
PreferenceCategory category = (PreferenceCategory)getPreferenceScreen().getPreference(0);
int index = 0;
for (String[] emojis : EasterDream.EMOJI_SETS) {
var listPreference = new ListPreference(getPreferenceScreen().getContext());
@SuppressLint("DefaultLocale")
String k = String.format("prob_%d", index);
listPreference.setKey(k);
listPreference.setDefaultValue("1");
listPreference.setEntries(R.array.probability_entries_values);
listPreference.setEntryValues(R.array.probability_entries_values);
listPreference.setSummaryProvider(ListPreference.SimpleSummaryProvider.getInstance());
listPreference.setTitle(getString(R.string.prob_fmt, String.join("", Arrays.copyOfRange(emojis, 0, Math.min(emojis.length, 5)))));
category.addPreference(listPreference);
index++;
}
}
}
}

View file

@ -0,0 +1,9 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/settings"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">EasterScrSaver</string>
<string name="title_activity_settings">设置</string>
<string name="daydream_header">屏保</string>
<string name="dim_screen_title">允许降低亮度</string>
<string name="switch_time_title">换页时间</string>
<string name="prob_fmt">%1$s 的出现频率</string>
<string name="permission_denied_read_external_storage">读取存储空间权限被拒绝,壁纸将不会显示</string>
<string name="error_title">错误</string>
<string name="button_ok"></string>
</resources>

View file

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="switch_time_entries">
<item>3600</item>
<item>300</item>
<item>60</item>
<item>30</item>
<item>10</item>
<item>5</item>
</string-array>
<string-array name="switch_time_values">
<item>3600</item>
<item>300</item>
<item>60</item>
<item>30</item>
<item>10</item>
<item>5</item>
</string-array>
<string-array name="probability_entries_values">
<item>100</item>
<item>50</item>
<item>20</item>
<item>10</item>
<item>9</item>
<item>8</item>
<item>7</item>
<item>6</item>
<item>5</item>
<item>4</item>
<item>3</item>
<item>2</item>
<item>1</item>
<item>0</item>
</string-array>
</resources>

View file

@ -1,3 +1,11 @@
<resources> <resources>
<string name="app_name">EasterScrSaver</string> <string name="app_name">EasterScrSaver</string>
</resources> <string name="title_activity_settings">Settings</string>
<string name="daydream_header">Daydream</string>
<string name="dim_screen_title">Screen Dimming</string>
<string name="switch_time_title">Switching time</string>
<string name="prob_fmt">Occur freq of %1$s</string>
<string name="permission_denied_read_external_storage">Storage read permission denied, wallpaper can\'t be shown</string>
<string name="error_title">Error occurred</string>
<string name="button_ok">OK</string>
</resources>

View file

@ -0,0 +1,2 @@
<dream xmlns:android="http://schemas.android.com/apk/res/android"
android:settingsActivity="cc.jerryxiao.easterscrsaver/.SettingsActivity" />

View file

@ -0,0 +1,22 @@
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory app:title="@string/daydream_header">
<SwitchPreferenceCompat
app:key="dim_screen"
app:title="@string/dim_screen_title"
app:defaultValue="false" />
<ListPreference
app:defaultValue="10"
app:entries="@array/switch_time_entries"
app:entryValues="@array/switch_time_values"
app:key="switch_time"
app:title="@string/switch_time_title"
app:useSimpleSummaryProvider="true" />
</PreferenceCategory>
</PreferenceScreen>

View file

@ -1,6 +1,6 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins { plugins {
id 'com.android.application' version '8.0.2' apply false id 'com.android.application' version '8.1.0' apply false
id 'com.android.library' version '8.0.2' apply false id 'com.android.library' version '8.1.0' apply false
id 'org.jetbrains.kotlin.android' version '1.9.0' apply false id 'org.jetbrains.kotlin.android' version '1.9.0' apply false
} }