├── .deepsource.toml
├── .github
└── workflows
│ ├── build.yml
│ └── release.yml
├── .gitignore
├── .idea
├── .gitignore
├── .name
├── compiler.xml
├── deploymentTargetDropDown.xml
├── discord.xml
├── gradle.xml
├── misc.xml
└── vcs.xml
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── abh80
│ │ └── smartedge
│ │ └── ExampleInstrumentedTest.java
│ ├── debug
│ └── AndroidManifest.xml
│ ├── github
│ └── AndroidManifest.xml
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── abh80
│ │ │ └── smartedge
│ │ │ ├── App.java
│ │ │ ├── activities
│ │ │ ├── AppearanceActivity.java
│ │ │ ├── MainActivity.java
│ │ │ ├── NotificationManageActivity.java
│ │ │ ├── OverlayLayoutSettingActivity.java
│ │ │ └── PermissionActivity.java
│ │ │ ├── plugins
│ │ │ ├── BasePlugin.java
│ │ │ ├── BatteryPlugin
│ │ │ │ └── BatteryPlugin.java
│ │ │ ├── ExportedPlugins.java
│ │ │ ├── MediaSession
│ │ │ │ ├── MediaCallback.java
│ │ │ │ ├── MediaSessionPlugin.java
│ │ │ │ ├── SongVisualizer.java
│ │ │ │ └── UpdateQueueStruct.java
│ │ │ └── Notification
│ │ │ │ ├── NotificationMeta.java
│ │ │ │ ├── NotificationPlugin.java
│ │ │ │ └── NotificationView.java
│ │ │ ├── services
│ │ │ ├── NotiService.java
│ │ │ ├── OverlayService.java
│ │ │ └── UpdaterService.java
│ │ │ ├── utils
│ │ │ ├── CallBack.java
│ │ │ ├── NotificationAppMeta.java
│ │ │ ├── NotificationHolderClass.java
│ │ │ ├── SettingStruct.java
│ │ │ └── adapters
│ │ │ │ ├── NotificationManageAppsAdapter.java
│ │ │ │ ├── NotificationViewPagerAdapter.java
│ │ │ │ └── RecylerViewSettingsAdapter.java
│ │ │ └── views
│ │ │ ├── BatteryImageView.java
│ │ │ └── ViewPagerOnClickable.java
│ └── res
│ │ ├── drawable-v24
│ │ ├── avd_pause_to_play.xml
│ │ ├── avd_play_to_pause.xml
│ │ ├── fast_forward.xml
│ │ ├── fast_rewind.xml
│ │ ├── launcher_foreground.png
│ │ ├── pause.xml
│ │ └── play.xml
│ │ ├── drawable
│ │ ├── custom_progress_bar_horizontal.xml
│ │ ├── default_dot.xml
│ │ ├── ic_baseline_add_24.xml
│ │ ├── ic_baseline_arrow_back_ios_24.xml
│ │ ├── ic_baseline_fast_forward_24.xml
│ │ ├── ic_baseline_fast_rewind_24.xml
│ │ ├── ic_baseline_message_24.xml
│ │ ├── ic_baseline_open_in_new_24.xml
│ │ ├── ic_baseline_pause_24.xml
│ │ ├── ic_baseline_play_arrow_24.xml
│ │ ├── ic_baseline_remove_24.xml
│ │ ├── ic_outline_refresh_24.xml
│ │ ├── ripple.xml
│ │ ├── rounded_corner.xml
│ │ ├── rounded_corner_setting_bottom.xml
│ │ ├── rounded_corner_setting_top.xml
│ │ ├── selected_dot.xml
│ │ └── tab_selector.xml
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ ├── activity_permission.xml
│ │ ├── appearence_layout.xml
│ │ ├── battery_layout.xml
│ │ ├── manage_notification_layout.xml
│ │ ├── media_session_layout.xml
│ │ ├── notification_layout.xml
│ │ ├── overlay_layout.xml
│ │ ├── overlay_layout_setting_activity.xml
│ │ ├── setting_custom_layout.xml
│ │ ├── single_notification.xml
│ │ ├── single_notification_layout_app.xml
│ │ ├── toggle_setting_layout.xml
│ │ └── toggle_setting_null_layout.xml
│ │ ├── menu
│ │ └── notifications_top_bar_menu.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── ids.xml
│ │ ├── strings.xml
│ │ ├── styles.xml
│ │ └── themes.xml
│ │ └── xml
│ │ ├── backup_rules.xml
│ │ ├── data_extraction_rules.xml
│ │ ├── global_action_bar_service.xml
│ │ ├── overlay_layout_scene.xml
│ │ └── provider_paths.xml
│ └── test
│ └── java
│ └── com
│ └── abh80
│ └── smartedge
│ └── ExampleUnitTest.java
├── build.gradle
├── fastlane
└── metadata
│ └── android
│ └── en-US
│ ├── changelogs
│ ├── 20202.txt
│ ├── 20203.txt
│ └── 20204.txt
│ ├── full_description.txt
│ ├── images
│ ├── icon.png
│ └── phoneScreenshots
│ │ └── screenshot.png
│ └── short_description.txt
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── package-lock.json
├── package.json
├── scripts
└── release.js
├── settings.gradle
└── yarn.lock
/.deepsource.toml:
--------------------------------------------------------------------------------
1 | version = 1
2 |
3 | [[analyzers]]
4 | name = "java"
5 | enabled = true
6 |
7 | [analyzers.meta]
8 | runtime_version = "13"
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build APK
2 |
3 | on:
4 | pull_request:
5 | types:
6 | - opened
7 |
8 | jobs:
9 | build:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: actions/checkout@v1
13 | - name: set up JDK 11
14 | uses: actions/setup-java@v1
15 | with:
16 | java-version: 11
17 | - name: Make Gradle executable
18 | run: chmod +x ./gradlew
19 | - name: Build with Gradle
20 | run: ./gradlew build
21 | - name: Build Release APK
22 | run: ./gradlew assembleRelease
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Build & Publish APK
2 |
3 | on: workflow_dispatch
4 |
5 | jobs:
6 | build:
7 | runs-on: ubuntu-latest
8 | strategy:
9 | matrix:
10 | node-version: [15.x]
11 | steps:
12 | - uses: actions/checkout@v1
13 | - name: set up JDK 11
14 | uses: actions/setup-java@v1
15 | with:
16 | java-version: 11
17 | - name: Decode Keystore
18 | uses: timheuer/base64-to-file@v1
19 | with:
20 | fileName: "keystore/keystore.jks"
21 | encodedString: ${{ secrets.ENCODED_KEYSTORE }}
22 | - name: Make Gradle executable
23 | run: chmod +x ./gradlew
24 | - name: Build with Gradle
25 | run: ./gradlew build
26 | env:
27 | SIGNING_KEY_PASSWORD: ${{ secrets.SIGNING_KEY_PASSWORD }}
28 | SIGNING_KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS }}
29 | - name: Build Release APK
30 | run: ./gradlew assembleGithub
31 | env:
32 | SIGNING_KEY_PASSWORD: ${{ secrets.SIGNING_KEY_PASSWORD }}
33 | SIGNING_KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS }}
34 | - name: Use Node.js ${{ matrix.node-version }}
35 | uses: actions/setup-node@v3
36 | with:
37 | node-version: ${{ matrix.node-version }}
38 | - name: Install Node Modules
39 | run: npm install
40 | - name: Publish Release
41 | run: node scripts/release.js
42 | env:
43 | TOKEN: ${{ secrets.TOKEN }}
44 | - name: Commit
45 | run: |
46 | git config --global user.name 'Github Actions'
47 | git config --global user.email 'action@github.com'
48 | git add .
49 | git commit -m "publish new build"
50 | - name: Push to Github
51 | uses: ad-m/github-push-action@master
52 | with:
53 | github_token: ${{ secrets.TOKEN }}
54 | force: true
55 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 | local.properties
16 | node_modules/
17 | keystore/
18 | .fleet
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | Smart Edge
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/deploymentTargetDropDown.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/.idea/discord.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
20 |
21 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Year abh80
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Smart Edge (Early Access) [](https://github.com/abh80/smart-edge/actions/workflows/release.yml)
2 | Alternative to dynamic island for android.
3 | # Downloads
4 |
5 | [](https://github.com/abh80/smart-edge/releases/download/20204/release.apk)
6 | # Donations
7 | Help support the project by donating ❤️
8 |
9 |
10 |
11 |
12 |
13 | # Previews
14 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | }
4 |
5 | android {
6 | compileSdk 32
7 | sourceSets {
8 | github {
9 | manifest.srcFile 'github/AndroidManifest.xml'
10 | }
11 | }
12 | defaultConfig {
13 | applicationId "com.abh80.smartedge"
14 | minSdk 26
15 | targetSdk 32
16 | versionCode 20204
17 | versionName "2.2.4"
18 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
19 | }
20 | signingConfigs {
21 | github {
22 | def tmpFilePath = System.getProperty("user.home") + "/work/_temp/keystore/keystore.jks"
23 | storeFile = file(tmpFilePath)
24 | storePassword System.getenv("SIGNING_KEY_PASSWORD")
25 | keyAlias System.getenv("SIGNING_KEY_ALIAS")
26 | keyPassword System.getenv("SIGNING_KEY_PASSWORD")
27 | }
28 | }
29 |
30 | buildTypes {
31 | github {
32 | minifyEnabled false
33 | buildConfigField "Boolean", "AUTO_UPDATE", "true"
34 | signingConfig signingConfigs.github
35 | }
36 | release {
37 | minifyEnabled false
38 | buildConfigField "Boolean", "AUTO_UPDATE", "false"
39 | }
40 | debug {
41 | minifyEnabled false
42 | buildConfigField "Boolean", "AUTO_UPDATE", "true"
43 | }
44 | }
45 | compileOptions {
46 | sourceCompatibility JavaVersion.VERSION_1_8
47 | targetCompatibility JavaVersion.VERSION_1_8
48 | }
49 | }
50 |
51 | dependencies {
52 |
53 | implementation 'androidx.appcompat:appcompat:1.5.0'
54 | implementation 'com.google.android.material:material:1.8.0-alpha01'
55 | testImplementation 'junit:junit:4.13.2'
56 | androidTestImplementation 'androidx.test.ext:junit:1.1.3'
57 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
58 | implementation 'org.apache.commons:commons-lang3:3.12.0'
59 | implementation 'com.android.volley:volley:1.2.1'
60 | implementation 'org.ocpsoft.prettytime:prettytime:5.0.2.Final'
61 | }
62 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/abh80/smartedge/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.abh80.smartedge;
2 |
3 | import android.content.Context;
4 |
5 | import androidx.test.platform.app.InstrumentationRegistry;
6 | import androidx.test.ext.junit.runners.AndroidJUnit4;
7 |
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 |
11 | import static org.junit.Assert.*;
12 |
13 | /**
14 | * Instrumented test, which will execute on an Android device.
15 | *
16 | * @see Testing documentation
17 | */
18 | @RunWith(AndroidJUnit4.class)
19 | public class ExampleInstrumentedTest {
20 | @Test
21 | public void useAppContext() {
22 | // Context of the app under test.
23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
24 | assertEquals("com.abh80.smartedge", appContext.getPackageName());
25 | }
26 | }
--------------------------------------------------------------------------------
/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/github/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
13 |
14 |
27 |
32 |
35 |
36 |
37 |
40 |
41 |
45 |
46 |
47 |
48 |
49 |
50 |
54 |
58 |
62 |
63 |
68 |
69 |
70 |
71 |
72 |
75 |
81 |
82 |
83 |
84 |
87 |
88 |
89 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/app/src/main/java/com/abh80/smartedge/App.java:
--------------------------------------------------------------------------------
1 | package com.abh80.smartedge;
2 |
3 | import android.app.Application;
4 |
5 | import com.google.android.material.color.DynamicColors;
6 |
7 | public class App extends Application {
8 | @Override
9 | public void onCreate() {
10 | super.onCreate();
11 | DynamicColors.applyToActivitiesIfAvailable(this);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/abh80/smartedge/activities/AppearanceActivity.java:
--------------------------------------------------------------------------------
1 | package com.abh80.smartedge.activities;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.content.SharedPreferences;
7 | import android.graphics.Color;
8 | import android.os.Bundle;
9 | import android.util.Log;
10 | import android.view.MenuItem;
11 | import android.view.inputmethod.InputMethodManager;
12 |
13 | import androidx.annotation.NonNull;
14 | import androidx.annotation.Nullable;
15 | import androidx.appcompat.app.AppCompatActivity;
16 |
17 | import com.abh80.smartedge.R;
18 | import com.google.android.material.snackbar.Snackbar;
19 | import com.google.android.material.textfield.TextInputLayout;
20 |
21 | import java.util.Objects;
22 | import java.util.regex.Matcher;
23 | import java.util.regex.Pattern;
24 |
25 | public class AppearanceActivity extends AppCompatActivity {
26 | private String intToHex(int i) {
27 | return Integer.toHexString(i);
28 | }
29 |
30 | @SuppressLint("RestrictedApi")
31 | @Override
32 | protected void onCreate(@Nullable Bundle savedInstanceState) {
33 | super.onCreate(savedInstanceState);
34 | setContentView(R.layout.appearence_layout);
35 | setSupportActionBar(findViewById(R.id.toolbar));
36 | Objects.requireNonNull(getSupportActionBar()).setDefaultDisplayHomeAsUpEnabled(true);
37 | SharedPreferences sharedPreferences = getSharedPreferences(getPackageName(), MODE_PRIVATE);
38 | TextInputLayout t = findViewById(R.id.textField);
39 | Objects.requireNonNull(t.getEditText()).setText(intToHex(sharedPreferences.getInt("color", getColor(R.color.black))));
40 | findViewById(R.id.apply_btn).setOnClickListener(l -> {
41 | String value = null;
42 | if (Objects.requireNonNull(t.getEditText()).getText() != null)
43 | value = "#" + t.getEditText().getText().toString();
44 | if (value != null) {
45 | if (isValidColor(value)) {
46 | t.setError(null);
47 | t.setErrorEnabled(false);
48 | try {
49 | InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
50 | imm.hideSoftInputFromWindow(findViewById(R.id.textField).getWindowToken(), 0);
51 | } catch (Exception ignored) {
52 | }
53 | try {
54 | int color = Color.parseColor(value);
55 | sharedPreferences.edit().putInt("color", color).apply();
56 | Snackbar.make(this, findViewById(R.id.textField), "Successfully updated color", Snackbar.LENGTH_SHORT).show();
57 | Intent intent = new Intent(getPackageName() + ".COLOR_CHANGED");
58 | intent.putExtra("color", color);
59 | sendBroadcast(intent);
60 | } catch (Exception e) {
61 | t.setErrorEnabled(true);
62 | t.setError("Invalid hexadecimal value");
63 | }
64 | } else {
65 | t.setErrorEnabled(true);
66 | t.setError("Please provide a valid hexadecimal value");
67 | }
68 |
69 | } else {
70 | t.setErrorEnabled(true);
71 | t.setError("Please provide a hexadecimal value");
72 | }
73 | });
74 | }
75 |
76 | private boolean isValidColor(String value) {
77 | // Source : https://stackoverflow.com/a/23155867/14200419
78 | Pattern colorPattern = Pattern.compile("#([0-9a-f]{6}|[0-9a-f]{8})");
79 | Matcher m = colorPattern.matcher(value);
80 | return m.matches();
81 | }
82 |
83 | @Override
84 | public boolean onOptionsItemSelected(@NonNull MenuItem item) {
85 | if (item.getItemId() == android.R.id.home) finish();
86 | return super.onOptionsItemSelected(item);
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/app/src/main/java/com/abh80/smartedge/activities/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.abh80.smartedge.activities;
2 |
3 | import android.Manifest;
4 | import android.annotation.SuppressLint;
5 | import android.app.Notification;
6 | import android.app.NotificationChannel;
7 | import android.app.NotificationManager;
8 | import android.content.BroadcastReceiver;
9 | import android.content.ClipData;
10 | import android.content.ClipboardManager;
11 | import android.content.Context;
12 | import android.content.Intent;
13 | import android.content.IntentFilter;
14 | import android.content.SharedPreferences;
15 | import android.content.pm.PackageManager;
16 | import android.graphics.Canvas;
17 | import android.graphics.Paint;
18 | import android.graphics.Rect;
19 | import android.graphics.drawable.Drawable;
20 | import android.net.Uri;
21 | import android.os.Bundle;
22 | import android.provider.Settings;
23 | import android.util.TypedValue;
24 | import android.view.View;
25 | import android.widget.Toast;
26 |
27 | import androidx.annotation.NonNull;
28 | import androidx.annotation.Nullable;
29 | import androidx.appcompat.app.AppCompatActivity;
30 | import androidx.core.app.ActivityCompat;
31 | import androidx.core.app.NotificationCompat;
32 | import androidx.recyclerview.widget.LinearLayoutManager;
33 | import androidx.recyclerview.widget.RecyclerView;
34 |
35 | import com.abh80.smartedge.BuildConfig;
36 | import com.abh80.smartedge.R;
37 | import com.abh80.smartedge.plugins.ExportedPlugins;
38 | import com.abh80.smartedge.services.UpdaterService;
39 | import com.abh80.smartedge.utils.adapters.RecylerViewSettingsAdapter;
40 | import com.abh80.smartedge.utils.SettingStruct;
41 | import com.google.android.material.bottomsheet.BottomSheetDialog;
42 | import com.google.android.material.card.MaterialCardView;
43 | import com.google.android.material.color.MaterialColors;
44 | import com.google.android.material.dialog.MaterialAlertDialogBuilder;
45 |
46 | import java.util.ArrayList;
47 | import java.util.Arrays;
48 |
49 | public class MainActivity extends AppCompatActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
50 | private SharedPreferences sharedPreferences;
51 | private final ArrayList settings = new ArrayList<>();
52 |
53 | @Override
54 | protected void onCreate(@Nullable Bundle savedInstanceState) {
55 | Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
56 | if (sharedPreferences.getBoolean("clip_copy_enabled", true)) {
57 | ClipboardManager clipboard = (ClipboardManager)
58 | getSystemService(Context.CLIPBOARD_SERVICE);
59 | ClipData clip = ClipData.newPlainText("smart edge error log", throwable.getMessage() + " : " + Arrays.toString(throwable.getStackTrace()));
60 | clipboard.setPrimaryClip(clip);
61 | sendCrashNotification();
62 | }
63 | Runtime.getRuntime().exit(0);
64 | });
65 | init();
66 | super.onCreate(savedInstanceState);
67 | setContentView(R.layout.activity_main);
68 | if ((Settings.Secure.getString(this.getContentResolver(), "enabled_notification_listeners") != null && !Settings.Secure.getString(this.getContentResolver(), "enabled_notification_listeners").contains(getApplicationContext().getPackageName())
69 | ) || ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
70 | startActivity(new Intent(this, PermissionActivity.class));
71 | }
72 | MaterialCardView enable_btn = findViewById(R.id.enable_switch);
73 | enable_btn.setOnClickListener(l -> {
74 | Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
75 | startActivity(intent);
76 | Toast.makeText(this, "Installed Apps -> Smart Edge", Toast.LENGTH_SHORT).show();
77 | });
78 | settings.add(new SettingStruct("Manage Overlay Layout", "App Settings", SettingStruct.TYPE_CUSTOM) {
79 | @Override
80 | public void onClick(Context c) {
81 | startActivity(new Intent(MainActivity.this, OverlayLayoutSettingActivity.class));
82 | }
83 | });
84 | settings.add(new SettingStruct("Overlay color", "App Settings", SettingStruct.TYPE_CUSTOM) {
85 | @Override
86 | public void onClick(Context ctx) {
87 | startActivity(new Intent(MainActivity.this, AppearanceActivity.class));
88 | }
89 | });
90 | if (BuildConfig.AUTO_UPDATE)
91 | settings.add(new SettingStruct("Enable auto update checking", "App Settings", SettingStruct.TYPE_TOGGLE) {
92 | @Override
93 | public boolean onAttach(Context ctx) {
94 | return sharedPreferences.getBoolean("update_enabled", true);
95 | }
96 |
97 | @Override
98 | public void onCheckChanged(boolean checked, Context ctx) {
99 | sharedPreferences.edit().putBoolean("update_enabled", checked).apply();
100 | }
101 | });
102 | settings.add(new SettingStruct("Invert long press and click functions", "App Settings", SettingStruct.TYPE_TOGGLE) {
103 | @Override
104 | public void onCheckChanged(boolean checked, Context ctx) {
105 | sharedPreferences.edit().putBoolean("invert_click", checked).apply();
106 | }
107 |
108 | @Override
109 | public boolean onAttach(Context ctx) {
110 | return sharedPreferences.getBoolean("invert_click", false);
111 | }
112 | });
113 | settings.add(new SettingStruct("Enable on lockscreen", "App Settings", SettingStruct.TYPE_TOGGLE) {
114 | @Override
115 | public boolean onAttach(Context ctx) {
116 | return sharedPreferences.getBoolean("enable_on_lockscreen", false);
117 | }
118 |
119 | @Override
120 | public void onCheckChanged(boolean checked, Context ctx) {
121 | sharedPreferences.edit().putBoolean("enable_on_lockscreen", checked).apply();
122 | }
123 | });
124 | settings.add(new SettingStruct("Copy crash logs to clipboard", "App Settings") {
125 | @Override
126 | public boolean onAttach(Context ctx) {
127 | return sharedPreferences.getBoolean("clip_copy_enabled", true);
128 | }
129 |
130 | @Override
131 | public void onCheckChanged(boolean checked, Context ctx) {
132 | sharedPreferences.edit().putBoolean("clip_copy_enabled", checked).apply();
133 | }
134 | });
135 | settings.add(null);
136 | ExportedPlugins.getPlugins().forEach(x -> {
137 | settings.add(new SettingStruct("Enable " + x.getName() + " Plugin", x.getName() + " Plugin Settings") {
138 | @Override
139 | public boolean onAttach(Context ctx) {
140 | return sharedPreferences.getBoolean(x.getID() + "_enabled", true);
141 | }
142 |
143 | @Override
144 | public void onCheckChanged(boolean checked, Context ctx) {
145 | sharedPreferences.edit().putBoolean(x.getID() + "_enabled", checked).apply();
146 | }
147 | }
148 | );
149 | if (x.getSettings() != null) {
150 | settings.addAll(x.getSettings());
151 | }
152 | settings.add(null);
153 | });
154 | RecylerViewSettingsAdapter adapter = new RecylerViewSettingsAdapter(this, settings);
155 | recyclerView = findViewById(R.id.recycler_view);
156 | recyclerView.setLayoutManager(new LinearLayoutManager(this));
157 | recyclerView.setAdapter(adapter);
158 | recyclerView.addItemDecoration(new ItemDecoration());
159 | recyclerView.invalidateItemDecorations();
160 | if (sharedPreferences.getBoolean("update_enabled", true) && BuildConfig.AUTO_UPDATE)
161 | startService(new Intent(this, UpdaterService.class));
162 | if (BuildConfig.AUTO_UPDATE)
163 | registerReceiver(broadcastReceiver, new IntentFilter(getPackageName() + ".UPDATE_AVAIL"));
164 |
165 | }
166 |
167 | private RecyclerView recyclerView;
168 |
169 | @Override
170 | protected void onResume() {
171 | super.onResume();
172 | sharedPreferences.registerOnSharedPreferenceChangeListener(this);
173 | }
174 |
175 | @Override
176 | protected void onPause() {
177 | super.onPause();
178 | sharedPreferences.unregisterOnSharedPreferenceChangeListener(this);
179 |
180 | }
181 |
182 | private void init() {
183 | if (sharedPreferences == null) {
184 |
185 | sharedPreferences = getSharedPreferences(getPackageName(), MODE_PRIVATE);
186 | }
187 | }
188 |
189 | @Override
190 | protected void onDestroy() {
191 | super.onDestroy();
192 | sharedPreferences.unregisterOnSharedPreferenceChangeListener(this);
193 | try {
194 | unregisterReceiver(broadcastReceiver);
195 | } catch (Exception ignored) {
196 | }
197 | }
198 |
199 | @Override
200 | public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
201 | Intent intent = new Intent(getPackageName() + ".SETTINGS_CHANGED");
202 | Bundle b = new Bundle();
203 | sharedPreferences.getAll().forEach((key, value) -> {
204 | if (value instanceof Boolean) {
205 | b.putBoolean(key, (boolean) value);
206 |
207 | }
208 | });
209 | intent.putExtra("settings", b);
210 | sendBroadcast(intent);
211 | }
212 |
213 | private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
214 | @Override
215 | public void onReceive(Context context, Intent intent) {
216 | if (intent.getAction().equals(getPackageName() + ".UPDATE_AVAIL")) {
217 | new MaterialAlertDialogBuilder(MainActivity.this).setTitle("New Update Available")
218 | .setMessage("We would like to update this app from " + BuildConfig.VERSION_NAME + " --> " + intent.getExtras().getString("version") +
219 | ".\n\nUpdating app generally means better and more stable experience.")
220 | .setCancelable(false)
221 | .setNegativeButton("Later", (dialogInterface, i) -> {
222 | dialogInterface.dismiss();
223 | })
224 | .setPositiveButton("Update Now", ((dialogInterface, i) -> {
225 | if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
226 | MainActivity.this.sendBroadcast(new Intent(getPackageName() + ".START_UPDATE"));
227 | Toast.makeText(MainActivity.this, "Updating in background! Please don't kill the app", Toast.LENGTH_SHORT).show();
228 | } else
229 | ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, 102);
230 | dialogInterface.dismiss();
231 | if (!getPackageManager().canRequestPackageInstalls()) {
232 | startActivityForResult(new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES)
233 | .setData(Uri.parse(String.format("package:%s", getPackageName()))), 103);
234 | Toast.makeText(MainActivity.this, "Please provide install access to update the application.", Toast.LENGTH_SHORT).show();
235 | }
236 | }))
237 | .show();
238 | }
239 | }
240 | };
241 |
242 | @Override
243 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
244 | super.onRequestPermissionsResult(requestCode, permissions, grantResults);
245 | if (requestCode == 102 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
246 | MainActivity.this.sendBroadcast(new Intent(getPackageName() + ".START_UPDATE"));
247 | Toast.makeText(MainActivity.this, "Updating in background! Please don't kill the app", Toast.LENGTH_SHORT).show();
248 | }
249 | }
250 |
251 | private int dpToInt(int v) {
252 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, v, getResources().getDisplayMetrics());
253 | }
254 |
255 | public class ItemDecoration extends RecyclerView.ItemDecoration {
256 | @SuppressLint("UseCompatLoadingForDrawables")
257 | @Override
258 | public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
259 | int color = MaterialColors.getColor(MainActivity.this, com.google.android.material.R.attr.colorOnSecondary, getColor(R.color.md_theme_dark_secondary));
260 | super.onDraw(c, parent, state);
261 | int childCount = recyclerView.getChildCount();
262 | int width = recyclerView.getWidth();
263 | Rect cornerBounds = new Rect();
264 | c.getClipBounds(cornerBounds);
265 | for (int i = 0; i < childCount; i++) {
266 | View childAt = recyclerView.getChildAt(i);
267 | RecylerViewSettingsAdapter.ViewHolder viewHolder = (RecylerViewSettingsAdapter.ViewHolder) recyclerView.getChildViewHolder(childAt);
268 | int vo = recyclerView.getChildAdapterPosition(childAt);
269 | if (!viewHolder.isItem) {
270 | if (settings.size() >= vo + 2 && settings.get(vo + 1) != null) {
271 | c.drawText(settings.get(vo + 1).category, cornerBounds.left + dpToInt(10), childAt.getBottom() - dpToInt(30), new Paint() {
272 | {
273 | setColor(MainActivity.this.getColor(R.color.quite_white));
274 | setTextSize(dpToInt(16));
275 | }
276 | });
277 | }
278 | Drawable cornerBottom = getDrawable(R.drawable.rounded_corner_setting_bottom);
279 | Drawable cornerTop = getDrawable(R.drawable.rounded_corner_setting_top);
280 | if (recyclerView.getChildAt(i + 1) != null) {
281 | View v = recyclerView.getChildAt(i + 1);
282 | cornerTop.setBounds(cornerBounds.left, (int) v.getY() - dpToInt(20), cornerBounds.right, (int) v.getY());
283 | cornerTop.draw(c);
284 | }
285 | if (recyclerView.getChildAt(i - 1) != null) {
286 | View v = recyclerView.getChildAt(i - 1);
287 | cornerBottom.setBounds(cornerBounds.left, v.getBottom(), cornerBounds.right, v.getBottom() + dpToInt(20));
288 | cornerBottom.draw(c);
289 | }
290 | } else {
291 | Rect bounds = new Rect(cornerBounds.left, (int) childAt.getY(), cornerBounds.right, childAt.getBottom());
292 | c.drawRect(bounds, new Paint() {
293 | {
294 | setColor(color);
295 | }
296 | });
297 | }
298 |
299 | }
300 | if (recyclerView.getChildCount() < 1) return;
301 | if (((RecylerViewSettingsAdapter.ViewHolder) recyclerView.getChildViewHolder(recyclerView.getChildAt(0))).isItem) {
302 | Drawable roundedCornerTop = getDrawable(R.drawable.rounded_corner_setting_top);
303 | roundedCornerTop.setBounds(cornerBounds.left, cornerBounds.top, cornerBounds.right, (int) recyclerView.getChildAt(0).getY());
304 | roundedCornerTop.draw(c);
305 | }
306 | if (((RecylerViewSettingsAdapter.ViewHolder) recyclerView.getChildViewHolder(recyclerView.getChildAt(recyclerView.getChildCount() - 1))).isItem) {
307 | Drawable roundedCornerBottom = getDrawable(R.drawable.rounded_corner_setting_bottom);
308 | roundedCornerBottom.setBounds(cornerBounds.left,
309 | recyclerView.getChildAt(recyclerView.getChildCount() - 1).getBottom(),
310 | cornerBounds.right,
311 | recyclerView.getChildAt(recyclerView.getChildCount() - 1).getBottom() + dpToInt(20));
312 | roundedCornerBottom.draw(c);
313 | }
314 | }
315 | }
316 |
317 | private void sendCrashNotification() {
318 | NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
319 | final String NOTIFICATION_CHANNEL_ID = getPackageName() + ".updater_channel";
320 | String channelName = "Updater Service";
321 | NotificationChannel chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_MIN);
322 | manager.createNotificationChannel(chan);
323 |
324 | NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);
325 | Notification notification = notificationBuilder.setOngoing(false)
326 | .setContentTitle("Smart Edge Crashed")
327 | .setContentText("Crash Log copied to clipboard")
328 | .setSmallIcon(R.drawable.launcher_foreground)
329 | .setPriority(NotificationManager.IMPORTANCE_MAX)
330 | .setCategory(Notification.CATEGORY_ERROR)
331 | .build();
332 | manager.notify(100, notification);
333 | }
334 | }
335 |
--------------------------------------------------------------------------------
/app/src/main/java/com/abh80/smartedge/activities/NotificationManageActivity.java:
--------------------------------------------------------------------------------
1 | package com.abh80.smartedge.activities;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Intent;
5 | import android.content.SharedPreferences;
6 | import android.content.pm.ApplicationInfo;
7 | import android.content.pm.PackageManager;
8 | import android.os.Bundle;
9 | import android.view.LayoutInflater;
10 | import android.view.Menu;
11 | import android.view.MenuItem;
12 |
13 | import androidx.annotation.NonNull;
14 | import androidx.annotation.Nullable;
15 | import androidx.appcompat.app.AppCompatActivity;
16 | import androidx.recyclerview.widget.LinearLayoutManager;
17 | import androidx.recyclerview.widget.RecyclerView;
18 |
19 | import com.abh80.smartedge.R;
20 | import com.abh80.smartedge.utils.NotificationAppMeta;
21 | import com.abh80.smartedge.utils.adapters.NotificationManageAppsAdapter;
22 | import com.google.android.material.appbar.MaterialToolbar;
23 |
24 | import org.apache.commons.lang3.StringUtils;
25 |
26 | import java.util.ArrayList;
27 | import java.util.List;
28 |
29 | public class NotificationManageActivity extends AppCompatActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
30 | private NotificationManageAppsAdapter adapter;
31 | private SharedPreferences sharedPreferences;
32 |
33 | @Override
34 | public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
35 | Intent intent = new Intent(getPackageName() + ".NOTIFICATION_APPS_UPDATE");
36 | intent.putExtra("apps", sharedPreferences.getString("notifications_apps", ""));
37 | sendBroadcast(intent);
38 | }
39 |
40 | @SuppressLint("RestrictedApi")
41 | @Override
42 | protected void onCreate(@Nullable Bundle savedInstanceState) {
43 | super.onCreate(savedInstanceState);
44 | setContentView(R.layout.manage_notification_layout);
45 | MaterialToolbar toolbar = findViewById(R.id.toolbar);
46 | setSupportActionBar(toolbar);
47 | sharedPreferences = getSharedPreferences(getPackageName(), MODE_PRIVATE);
48 | getSupportActionBar().setDefaultDisplayHomeAsUpEnabled(true);
49 | RecyclerView recyclerView = findViewById(R.id.recycler_view);
50 | recyclerView.setLayoutManager(new LinearLayoutManager(this));
51 | ArrayList apps = new ArrayList<>();
52 | ArrayList apps_enabled = NotificationManageAppsAdapter.parseEnabledApps(sharedPreferences.getString("notifications_apps", ""));
53 | // avoid blocking ui
54 | new Thread(() -> {
55 | List infos = getPackageManager().getInstalledApplications(PackageManager.GET_META_DATA);
56 | for (ApplicationInfo info : infos) {
57 | if (((info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) || ((info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0)) {
58 | NotificationAppMeta meta = new NotificationAppMeta(getPackageManager().getApplicationLabel(info).toString(), info.packageName, info.loadIcon(getPackageManager()));
59 | meta.enabled = apps_enabled.contains("all") || apps_enabled.contains(info.packageName);
60 | apps.add(meta);
61 | }
62 | }
63 | runOnUiThread(() -> {
64 | adapter = new NotificationManageAppsAdapter(sharedPreferences, apps);
65 | recyclerView.setAdapter(adapter);
66 | });
67 | }).start();
68 | sharedPreferences.registerOnSharedPreferenceChangeListener(this);
69 | }
70 |
71 | @Override
72 | protected void onDestroy() {
73 | super.onDestroy();
74 | adapter = null;
75 | sharedPreferences.unregisterOnSharedPreferenceChangeListener(this);
76 | }
77 |
78 | @Override
79 | public boolean onPrepareOptionsMenu(@NonNull Menu menu) {
80 | getMenuInflater().inflate(R.menu.notifications_top_bar_menu, menu);
81 | return super.onPrepareOptionsMenu(menu);
82 | }
83 |
84 | @SuppressLint("NotifyDataSetChanged")
85 | @Override
86 | public boolean onOptionsItemSelected(@NonNull MenuItem item) {
87 | if (item.getItemId() == android.R.id.home) {
88 | finish();
89 | return true;
90 | } else {
91 | if (adapter.apps != null) {
92 | if (adapter.apps.stream().anyMatch(x -> x.enabled)) {
93 | for (NotificationAppMeta app : adapter.apps) {
94 | app.enabled = false;
95 | }
96 | sharedPreferences.edit().putString("notifications_apps", "").apply();
97 | } else {
98 | for (NotificationAppMeta app : adapter.apps) {
99 | app.enabled = true;
100 | }
101 | sharedPreferences.edit().putString("notifications_apps", StringUtils.join(adapter.apps.stream().map(x -> x.package_name).toArray(), ",")).apply();
102 | }
103 | adapter.notifyDataSetChanged();
104 | }
105 | }
106 | return super.onOptionsItemSelected(item);
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/app/src/main/java/com/abh80/smartedge/activities/OverlayLayoutSettingActivity.java:
--------------------------------------------------------------------------------
1 | package com.abh80.smartedge.activities;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Intent;
5 | import android.content.SharedPreferences;
6 | import android.content.res.Resources;
7 | import android.os.Bundle;
8 | import android.util.DisplayMetrics;
9 | import android.util.TypedValue;
10 | import android.view.MenuItem;
11 | import android.widget.TextView;
12 |
13 | import androidx.annotation.NonNull;
14 | import androidx.annotation.Nullable;
15 | import androidx.appcompat.app.AppCompatActivity;
16 |
17 | import com.abh80.smartedge.R;
18 | import com.google.android.material.imageview.ShapeableImageView;
19 | import com.google.android.material.slider.Slider;
20 |
21 | import java.math.RoundingMode;
22 | import java.text.DecimalFormat;
23 |
24 | public class OverlayLayoutSettingActivity extends AppCompatActivity {
25 | SharedPreferences sharedPreferences;
26 | Slider h;
27 | TextView val_h;
28 | ShapeableImageView add_h;
29 | ShapeableImageView sub_h;
30 |
31 | Slider gap;
32 | TextView val_gap;
33 | ShapeableImageView add_gap;
34 | ShapeableImageView sub_gap;
35 |
36 | Slider x;
37 | TextView val_x;
38 | ShapeableImageView add_x;
39 | ShapeableImageView sub_x;
40 |
41 | Slider w;
42 | ShapeableImageView add_w;
43 | ShapeableImageView sub_w;
44 |
45 | Slider y;
46 | TextView val_y;
47 | ShapeableImageView add_y;
48 | ShapeableImageView sub_y;
49 |
50 | @SuppressLint("RestrictedApi")
51 | @Override
52 | protected void onCreate(@Nullable Bundle savedInstanceState) {
53 | DisplayMetrics metrics = getResources().getDisplayMetrics();
54 | super.onCreate(savedInstanceState);
55 | setContentView(R.layout.overlay_layout_setting_activity);
56 | setSupportActionBar(findViewById(R.id.toolbar));
57 | assert getSupportActionBar() != null;
58 | getSupportActionBar().setDefaultDisplayHomeAsUpEnabled(true);
59 | sharedPreferences = getSharedPreferences(getPackageName(), MODE_PRIVATE);
60 | h = findViewById(R.id.seekbar_h);
61 | val_h = findViewById(R.id.val_h);
62 | add_h = findViewById(R.id.add_h);
63 | sub_h = findViewById(R.id.sub_h);
64 |
65 | gap = findViewById(R.id.seekbar_gap);
66 | val_gap = findViewById(R.id.val_gap);
67 | add_gap = findViewById(R.id.add_gap);
68 | sub_gap = findViewById(R.id.sub_gap);
69 |
70 | x = findViewById(R.id.seekbar_x);
71 | val_x = findViewById(R.id.val_x);
72 | add_x = findViewById(R.id.add_x);
73 | sub_x = findViewById(R.id.sub_x);
74 |
75 | w = findViewById(R.id.seekbar_w);
76 | add_w = findViewById(R.id.add_w);
77 | sub_w = findViewById(R.id.sub_w);
78 | val_w = findViewById(R.id.val_w);
79 |
80 | y = findViewById(R.id.seekbar_y);
81 | val_y = findViewById(R.id.val_y);
82 |
83 | add_w.setOnClickListener(l -> {
84 | int v = (int) w.getValue();
85 | v += 1;
86 | if (v >= w.getValueTo()) v = (int) w.getValueTo();
87 | if (v <= w.getValueFrom()) v = (int) w.getValueFrom();
88 | w.setValue(v);
89 | onChange();
90 | });
91 | sub_w.setOnClickListener(l -> {
92 | int v = (int) w.getValue();
93 | v -= 1;
94 | if (v >= w.getValueTo()) v = (int) w.getValueTo();
95 | if (v <= w.getValueFrom()) v = (int) w.getValueFrom();
96 | w.setValue(v);
97 | onChange();
98 | });
99 | add_h.setOnClickListener(l -> {
100 | int v = (int) h.getValue();
101 | v += 1;
102 | if (v >= h.getValueTo()) v = (int) h.getValueTo();
103 | if (v <= h.getValueFrom()) v = (int) h.getValueFrom();
104 | h.setValue(v);
105 | onChange();
106 | });
107 | sub_h.setOnClickListener(l -> {
108 | int v = (int) h.getValue();
109 | v -= 1;
110 | if (v >= h.getValueTo()) v = (int) h.getValueTo();
111 | if (v <= h.getValueFrom()) v = (int) h.getValueFrom();
112 | h.setValue(v);
113 | onChange();
114 | });
115 | add_gap.setOnClickListener(l -> {
116 | int v = (int) gap.getValue();
117 | v += 1;
118 | if (v >= gap.getValueTo()) v = (int) gap.getValueTo();
119 | if (v <= gap.getValueFrom()) v = (int) gap.getValueFrom();
120 | gap.setValue(v);
121 | onChange();
122 | });
123 | sub_gap.setOnClickListener(l -> {
124 | int v = (int) gap.getValue();
125 | v -= 1;
126 | if (v >= gap.getValueTo()) v = (int) gap.getValueTo();
127 | if (v <= gap.getValueFrom()) v = (int) gap.getValueFrom();
128 | gap.setValue(v);
129 | onChange();
130 | });
131 | add_y = findViewById(R.id.add_y);
132 | sub_y = findViewById(R.id.sub_y);
133 |
134 | add_y.setOnClickListener(l -> {
135 | float v = y.getValue();
136 | v += 0.1;
137 | if (v >= y.getValueTo()) v = y.getValueTo();
138 | if (v <= y.getValueFrom()) v = y.getValueFrom();
139 | y.setValue(v);
140 | onChange();
141 | });
142 | sub_y.setOnClickListener(l -> {
143 | float v = y.getValue();
144 | v -= 0.1;
145 | if (v >= y.getValueTo()) v = y.getValueTo();
146 | if (v <= y.getValueFrom()) v = y.getValueFrom();
147 | y.setValue(v);
148 | onChange();
149 | });
150 | add_x.setOnClickListener(l -> {
151 | float v = x.getValue();
152 | v += 0.1;
153 | if (Math.abs(v) < 0.1) v = 0;
154 | if (v >= x.getValueTo()) v = x.getValueTo();
155 | if (v <= x.getValueFrom()) v = x.getValueFrom();
156 | x.setValue(v);
157 | onChange();
158 | });
159 | sub_x.setOnClickListener(l -> {
160 | float v = x.getValue();
161 | v -= 0.1;
162 | if (v >= x.getValueTo()) v = x.getValueTo();
163 | if (v <= x.getValueFrom()) v = x.getValueFrom();
164 | x.setValue(v);
165 | onChange();
166 | });
167 |
168 | y.addOnChangeListener((slider, value, fromUser) -> {
169 | if (fromUser) onChange();
170 | });
171 | x.addOnChangeListener((slider, value, fromUser) -> {
172 | if (fromUser) onChange();
173 | });
174 | h.addOnChangeListener((slider, value, fromUser) -> {
175 | if (fromUser) onChange();
176 | });
177 | w.addOnChangeListener((slider, value, fromUser) -> {
178 | if (fromUser) onChange();
179 | });
180 | gap.addOnChangeListener((slider, value, fromUser) -> {
181 | if (fromUser) onChange();
182 | });
183 |
184 | gap.setValue(sharedPreferences.getFloat("overlay_gap", 50));
185 | w.setValue(sharedPreferences.getFloat("overlay_w", 83));
186 | h.setValue(sharedPreferences.getFloat("overlay_h", 40));
187 | x.setValue(sharedPreferences.getFloat("overlay_x", 0));
188 | y.setValue(sharedPreferences.getFloat("overlay_y", 0.67f));
189 | updateTexts();
190 | findViewById(R.id.reset_btn).setOnClickListener(l -> {
191 | gap.setValue(40);
192 | w.setValue(100);
193 | h.setValue(40);
194 | x.setValue(0);
195 | y.setValue(0.1f);
196 | onChange();
197 | });
198 |
199 | }
200 |
201 | TextView val_w;
202 |
203 | @SuppressLint("SetTextI18n")
204 | private void updateTexts() {
205 | DecimalFormat df = new DecimalFormat("##.##");
206 | df.setRoundingMode(RoundingMode.DOWN);
207 | val_gap.setText(df.format(gap.getValue()) + " dp");
208 | val_x.setText(df.format(x.getValue()) + " %");
209 | val_y.setText(df.format(y.getValue()) + " %");
210 | val_h.setText(df.format(h.getValue()) + " dp");
211 | val_w.setText(df.format(w.getValue()) + " dp");
212 | }
213 |
214 | private void onChange() {
215 | sharedPreferences.edit().putFloat("overlay_w", w.getValue()).apply();
216 | sharedPreferences.edit().putFloat("overlay_h", h.getValue()).apply();
217 | sharedPreferences.edit().putFloat("overlay_gap", gap.getValue()).apply();
218 | sharedPreferences.edit().putFloat("overlay_x", x.getValue()).apply();
219 | sharedPreferences.edit().putFloat("overlay_y", y.getValue()).apply();
220 | updateTexts();
221 | Intent intent = new Intent(getPackageName() + ".OVERLAY_LAYOUT_CHANGE");
222 | Bundle b = new Bundle();
223 | sharedPreferences.getAll().forEach((key, val) -> {
224 | if (val instanceof Float) {
225 | b.putFloat(key, (float) val);
226 | }
227 | });
228 | intent.putExtra("settings", b);
229 | sendBroadcast(intent);
230 | }
231 |
232 | private float pxToDp(int x) {
233 | DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
234 | return x / (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT);
235 | }
236 |
237 | @Override
238 | public boolean onOptionsItemSelected(@NonNull MenuItem item) {
239 | if (item.getItemId() == android.R.id.home) {
240 | finish();
241 | return true;
242 | }
243 | return super.onOptionsItemSelected(item);
244 | }
245 | }
246 |
--------------------------------------------------------------------------------
/app/src/main/java/com/abh80/smartedge/activities/PermissionActivity.java:
--------------------------------------------------------------------------------
1 | package com.abh80.smartedge.activities;
2 |
3 | import android.Manifest;
4 | import android.content.Intent;
5 | import android.content.pm.PackageManager;
6 | import android.net.Uri;
7 | import android.os.Bundle;
8 | import android.provider.Settings;
9 | import android.widget.CheckBox;
10 | import android.widget.Toast;
11 |
12 | import androidx.annotation.NonNull;
13 | import androidx.annotation.Nullable;
14 | import androidx.appcompat.app.AppCompatActivity;
15 | import androidx.core.app.ActivityCompat;
16 |
17 | import com.abh80.smartedge.R;
18 |
19 | public class PermissionActivity extends AppCompatActivity {
20 | @Override
21 | protected void onCreate(@Nullable Bundle savedInstanceState) {
22 | super.onCreate(savedInstanceState);
23 | setContentView(R.layout.activity_permission);
24 | findViewById(R.id.notification_access).setOnClickListener(l -> {
25 | if (Settings.Secure.getString(this.getContentResolver(), "enabled_notification_listeners") != null && Settings.Secure.getString(this.getContentResolver(), "enabled_notification_listeners").contains(getApplicationContext().getPackageName())) {
26 | Toast.makeText(this, "This permission is already enabled", Toast.LENGTH_LONG).show();
27 | return;
28 | }
29 | startActivity(new Intent(
30 | "android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"));
31 | Toast.makeText(this, "Please select Smart Edge", Toast.LENGTH_LONG).show();
32 | });
33 | findViewById(R.id.record_audio).setOnClickListener(l -> {
34 | if (ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) {
35 | Toast.makeText(this, "This permission is already enabled", Toast.LENGTH_LONG).show();
36 | return;
37 | }
38 | ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, 101);
39 | });
40 | }
41 |
42 | @Override
43 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
44 | super.onRequestPermissionsResult(requestCode, permissions, grantResults);
45 | onResume();
46 | }
47 |
48 | @Override
49 | protected void onResume() {
50 | super.onResume();
51 | int checks = 0;
52 | if (Settings.Secure.getString(this.getContentResolver(), "enabled_notification_listeners") != null && Settings.Secure.getString(this.getContentResolver(), "enabled_notification_listeners").contains(getApplicationContext().getPackageName())) {
53 | ((CheckBox) findViewById(R.id.notification_access_checkbox)).setChecked(true);
54 | checks++;
55 | }
56 | if (ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) {
57 | ((CheckBox) findViewById(R.id.record_audio_checkbox)).setChecked(true);
58 | checks++;
59 | }
60 | if (checks >= 2) {
61 | finish();
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/app/src/main/java/com/abh80/smartedge/plugins/BasePlugin.java:
--------------------------------------------------------------------------------
1 | package com.abh80.smartedge.plugins;
2 |
3 | import android.view.View;
4 | import android.view.accessibility.AccessibilityEvent;
5 |
6 | import com.abh80.smartedge.services.OverlayService;
7 | import com.abh80.smartedge.utils.SettingStruct;
8 |
9 | import java.util.ArrayList;
10 |
11 | public abstract class BasePlugin {
12 | public abstract String getID();
13 |
14 | public abstract String getName();
15 |
16 | public abstract void onCreate(OverlayService context);
17 |
18 | public abstract View onBind();
19 |
20 | public abstract void onUnbind();
21 |
22 | public abstract void onDestroy();
23 |
24 | public abstract void onExpand();
25 |
26 | public abstract void onCollapse();
27 |
28 | public abstract void onClick();
29 |
30 | public void onTextColorChange() {
31 | }
32 |
33 | public abstract String[] permissionsRequired();
34 |
35 | public void onEvent(AccessibilityEvent event) {
36 | }
37 |
38 | public abstract ArrayList getSettings();
39 |
40 | public void onBindComplete() {
41 | }
42 |
43 | public void onRightSwipe() {
44 | }
45 |
46 | public void onLeftSwipe() {
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/app/src/main/java/com/abh80/smartedge/plugins/BatteryPlugin/BatteryPlugin.java:
--------------------------------------------------------------------------------
1 | package com.abh80.smartedge.plugins.BatteryPlugin;
2 |
3 | import android.animation.Animator;
4 | import android.animation.AnimatorListenerAdapter;
5 | import android.animation.ValueAnimator;
6 | import android.content.BroadcastReceiver;
7 | import android.content.Context;
8 | import android.content.Intent;
9 | import android.content.IntentFilter;
10 | import android.graphics.Color;
11 | import android.os.BatteryManager;
12 | import android.view.LayoutInflater;
13 | import android.view.View;
14 | import android.view.ViewGroup;
15 | import android.widget.TextView;
16 |
17 | import com.abh80.smartedge.R;
18 | import com.abh80.smartedge.plugins.BasePlugin;
19 | import com.abh80.smartedge.services.OverlayService;
20 | import com.abh80.smartedge.utils.SettingStruct;
21 | import com.abh80.smartedge.views.BatteryImageView;
22 |
23 | import java.util.ArrayList;
24 |
25 | public class BatteryPlugin extends BasePlugin {
26 | @Override
27 | public String getID() {
28 | return "BatteryPlugin";
29 | }
30 |
31 | @Override
32 | public String getName() {
33 | return "Battery Plugin";
34 | }
35 |
36 | private OverlayService ctx;
37 |
38 | @Override
39 | public void onCreate(OverlayService context) {
40 | ctx = context;
41 | ctx.registerReceiver(mBroadcastReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
42 | }
43 |
44 | private View mView;
45 |
46 | @Override
47 | public View onBind() {
48 | mView = LayoutInflater.from(ctx).inflate(R.layout.battery_layout, null);
49 | init();
50 | return mView;
51 | }
52 |
53 | private void init() {
54 | tv = mView.findViewById(R.id.text_percent);
55 | batteryImageView = mView.findViewById(R.id.cover);
56 | updateView();
57 | }
58 |
59 | float batteryPercent;
60 | private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
61 | @Override
62 | public void onReceive(Context context, Intent intent) {
63 | int status = intent.getExtras().getInt(BatteryManager.EXTRA_STATUS);
64 | boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING;
65 | if (isCharging) {
66 | ctx.enqueue(BatteryPlugin.this);
67 | int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
68 | int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
69 | batteryPercent = level * 100 / (float) scale;
70 | updateView();
71 | } else {
72 | ctx.dequeue(BatteryPlugin.this);
73 | if (tv != null && batteryImageView != null) {
74 | ValueAnimator valueAnimator = ValueAnimator.ofInt(0, ctx.dpToInt(0));
75 | valueAnimator.setDuration(300);
76 | valueAnimator.addUpdateListener(valueAnimator1 -> {
77 | ViewGroup.LayoutParams p = batteryImageView.getLayoutParams();
78 | p.width = (int) valueAnimator1.getAnimatedValue();
79 | p.height = (int) valueAnimator1.getAnimatedValue();
80 | batteryImageView.setLayoutParams(p);
81 | });
82 | valueAnimator.addListener(new AnimatorListenerAdapter() {
83 | @Override
84 | public void onAnimationStart(Animator animation) {
85 | super.onAnimationEnd(animation);
86 | tv.setVisibility(View.INVISIBLE);
87 | }
88 | });
89 | valueAnimator.start();
90 | }
91 | }
92 | }
93 | };
94 | private TextView tv;
95 | private BatteryImageView batteryImageView;
96 |
97 | private void updateView() {
98 | if (mView != null) {
99 | tv.setText((int) batteryPercent + "%");
100 | batteryImageView.updateBatteryPercent(batteryPercent);
101 | if (batteryPercent > 80) {
102 | batteryImageView.setStrokeColor(Color.GREEN);
103 | tv.setTextColor(Color.GREEN);
104 | } else if (batteryPercent < 80 && batteryPercent > 20) {
105 | batteryImageView.setStrokeColor(Color.YELLOW);
106 | tv.setTextColor(Color.YELLOW);
107 | } else {
108 | batteryImageView.setStrokeColor(Color.RED);
109 | tv.setTextColor(Color.RED);
110 | }
111 | }
112 | }
113 |
114 | @Override
115 | public void onUnbind() {
116 |
117 | mView = null;
118 | }
119 |
120 | @Override
121 | public void onBindComplete() {
122 | if (mView == null) return;
123 | ValueAnimator valueAnimator = ValueAnimator.ofInt(0, ctx.dpToInt(ctx.minHeight / 4));
124 | valueAnimator.setDuration(300);
125 | valueAnimator.addUpdateListener(valueAnimator1 -> {
126 | ViewGroup.LayoutParams p = batteryImageView.getLayoutParams();
127 | p.width = (int) valueAnimator1.getAnimatedValue();
128 | p.height = (int) valueAnimator1.getAnimatedValue();
129 | batteryImageView.setLayoutParams(p);
130 | });
131 | valueAnimator.addListener(new AnimatorListenerAdapter() {
132 | @Override
133 | public void onAnimationEnd(Animator animation) {
134 | super.onAnimationEnd(animation);
135 | tv.setVisibility(View.VISIBLE);
136 | batteryImageView.requestLayout();
137 | batteryImageView.updateBatteryPercent(batteryPercent);
138 | }
139 | });
140 | valueAnimator.start();
141 | }
142 |
143 | @Override
144 | public void onDestroy() {
145 | ctx.unregisterReceiver(mBroadcastReceiver);
146 | }
147 |
148 | @Override
149 | public void onExpand() {
150 |
151 | }
152 |
153 | @Override
154 | public void onCollapse() {
155 |
156 | }
157 |
158 | @Override
159 | public void onClick() {
160 |
161 | }
162 |
163 | @Override
164 | public String[] permissionsRequired() {
165 | return null;
166 | }
167 |
168 | @Override
169 | public ArrayList getSettings() {
170 | return null;
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/app/src/main/java/com/abh80/smartedge/plugins/ExportedPlugins.java:
--------------------------------------------------------------------------------
1 | package com.abh80.smartedge.plugins;
2 |
3 | import com.abh80.smartedge.plugins.BatteryPlugin.BatteryPlugin;
4 | import com.abh80.smartedge.plugins.MediaSession.MediaSessionPlugin;
5 | import com.abh80.smartedge.plugins.Notification.NotificationPlugin;
6 |
7 | import java.util.ArrayList;
8 |
9 | public class ExportedPlugins {
10 | public static ArrayList getPlugins() {
11 | ArrayList plugins = new ArrayList<>();
12 | plugins.add(new MediaSessionPlugin());
13 | plugins.add(new NotificationPlugin());
14 | plugins.add(new BatteryPlugin());
15 | return plugins;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/abh80/smartedge/plugins/MediaSession/MediaCallback.java:
--------------------------------------------------------------------------------
1 | package com.abh80.smartedge.plugins.MediaSession;
2 |
3 | import android.graphics.Bitmap;
4 | import android.media.MediaMetadata;
5 | import android.media.session.MediaController;
6 | import android.media.session.PlaybackState;
7 |
8 | import androidx.annotation.Nullable;
9 |
10 | import com.abh80.smartedge.utils.CallBack;
11 |
12 | public class MediaCallback extends MediaController.Callback {
13 | public MediaCallback(MediaController mCurrent, MediaSessionPlugin context) {
14 | this.mCurrent = mCurrent;
15 | this.ctx = context;
16 | try {
17 | isPlaying = mCurrent.getPlaybackState().getState() == PlaybackState.STATE_PLAYING;
18 | mediaMetadata = mCurrent.getMetadata();
19 | updateView();
20 | } catch (Exception e) {
21 | // do nothing lol
22 | }
23 | }
24 |
25 | private final MediaSessionPlugin ctx;
26 | private final MediaController mCurrent;
27 | private MediaMetadata mediaMetadata;
28 | private boolean isPlaying = true;
29 |
30 | private void updateView() {
31 | if (!isPlaying) return;
32 | if (mCurrent.getMetadata() == null) return;
33 | Bitmap b = mediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
34 | if (b == null) {
35 | return;
36 | }
37 | String title = mediaMetadata.getText(MediaMetadata.METADATA_KEY_TITLE).toString();
38 | String artist = mediaMetadata.getString(MediaMetadata.METADATA_KEY_ARTIST);
39 | ctx.queueUpdate(new UpdateQueueStruct(artist, title, b));
40 | ctx.openOverlay(mCurrent.getPackageName());
41 | ctx.mCurrent = mCurrent;
42 | ctx.onPlayerResume(false);
43 | }
44 |
45 |
46 | @Override
47 | public void onPlaybackStateChanged(@Nullable PlaybackState state) {
48 | super.onPlaybackStateChanged(state);
49 | try {
50 | if (state == null || mCurrent.getMetadata() == null) return;
51 | MediaMetadata targetMetada = mCurrent.getMetadata();
52 | boolean isPlaying2 = state.getState() == PlaybackState.STATE_PLAYING;
53 | if (mediaMetadata != null && mediaMetadata.getString(MediaMetadata.METADATA_KEY_TITLE) != null
54 | && mediaMetadata.getString(MediaMetadata.METADATA_KEY_TITLE).equals(targetMetada.getString(MediaMetadata.METADATA_KEY_TITLE)) && ctx.overlayOpen()) {
55 | if (ctx.mCurrent != null && ctx.mCurrent.getPackageName().equals(mCurrent.getPackageName())) {
56 | if (!isPlaying2) ctx.onPlayerPaused(true);
57 | else ctx.onPlayerResume(true);
58 | }
59 | isPlaying = isPlaying2;
60 | return;
61 | }
62 |
63 | isPlaying = isPlaying2;
64 | if (ctx.mCurrent != null && ctx.mCurrent.getPackageName().equals(mCurrent.getPackageName())) {
65 | if (!isPlaying) ctx.onPlayerPaused(false);
66 | else ctx.onPlayerResume(false);
67 | }
68 | if (!isPlaying) return;
69 | mediaMetadata = targetMetada;
70 | ctx.mCurrent = mCurrent;
71 | if (ctx.expanded) {
72 | updateView();
73 | return;
74 | }
75 | ctx.closeOverlay(new CallBack() {
76 | @Override
77 | public void onFinish() {
78 | super.onFinish();
79 | updateView();
80 | }
81 | });
82 | } catch (Exception e) {
83 | e.printStackTrace();
84 | ctx.closeOverlay();
85 | }
86 | }
87 |
88 | @Override
89 | public void onSessionDestroyed() {
90 | super.onSessionDestroyed();
91 | if (mCurrent != null) {
92 | mCurrent.unregisterCallback(this);
93 | ctx.callbackMap.remove(mCurrent.getPackageName());
94 | ctx.mCurrent = null;
95 | }
96 | ctx.closeOverlay();
97 |
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/app/src/main/java/com/abh80/smartedge/plugins/MediaSession/SongVisualizer.java:
--------------------------------------------------------------------------------
1 | package com.abh80.smartedge.plugins.MediaSession;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Color;
6 | import android.graphics.Paint;
7 | import android.media.audiofx.Visualizer;
8 | import android.util.AttributeSet;
9 | import android.view.View;
10 |
11 | import androidx.annotation.Nullable;
12 |
13 | public class SongVisualizer extends View {
14 | Visualizer visualizer;
15 |
16 | public SongVisualizer(Context context) {
17 | super(context);
18 | init();
19 | }
20 |
21 | public SongVisualizer(Context context, @Nullable AttributeSet attrs) {
22 | super(context, attrs);
23 | init();
24 | }
25 |
26 | public SongVisualizer(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
27 | super(context, attrs, defStyleAttr);
28 | init();
29 | }
30 |
31 | public boolean paused;
32 | private byte[] bytes;
33 |
34 | public void setPlayerId(int sessionID) {
35 | try {
36 | if (visualizer != null) {
37 | release();
38 | visualizer = null;
39 | }
40 | visualizer = new Visualizer(sessionID);
41 | visualizer.setEnabled(false);
42 | visualizer.setScalingMode(Visualizer.SCALING_MODE_NORMALIZED);
43 | visualizer.setCaptureSize(Visualizer.getCaptureSizeRange()[1]);
44 | visualizer.setDataCaptureListener(new Visualizer.OnDataCaptureListener() {
45 | @Override
46 | public void onWaveFormDataCapture(Visualizer visualizer, byte[] bytes,
47 | int samplingRate) {
48 | SongVisualizer.this.bytes = bytes;
49 | if (!paused) invalidate();
50 | }
51 |
52 | @Override
53 | public void onFftDataCapture(Visualizer visualizer, byte[] bytes,
54 | int samplingRate) {
55 | }
56 | }, Visualizer.getMaxCaptureRate() / 2, true, false);
57 |
58 |
59 | visualizer.setEnabled(true);
60 | } catch (Exception e) {
61 | // do nothing lol
62 | }
63 | }
64 |
65 | public void release() {
66 | //will be null if setPlayer hasn't yet been called
67 | if (visualizer == null)
68 | return;
69 |
70 | visualizer.release();
71 | bytes = null;
72 | invalidate();
73 | }
74 |
75 | private void init() {
76 | setColor(Color.BLUE);
77 | paint.setStyle(Paint.Style.FILL);
78 | paint.setStrokeCap(Paint.Cap.ROUND);
79 | }
80 |
81 | public void setColor(int Color) {
82 | paint.setColor(Color);
83 | }
84 |
85 | private final Paint paint = new Paint();
86 |
87 | @Override
88 | protected void onDraw(Canvas canvas) {
89 | float density = 8;
90 |
91 | if (bytes != null) {
92 | float barWidth = getWidth() / density;
93 | float div = bytes.length / density;
94 | paint.setStrokeWidth(barWidth - 4);
95 |
96 | for (int i = 0; i < density; i++) {
97 | int bytePosition = (int) Math.ceil(i * div);
98 | float barX = (i * barWidth) + (barWidth / 2);
99 | if (bytes[bytePosition] == 0 || bytes[bytePosition] + 128 == 0) {
100 | canvas.drawLine(barX, (getHeight() / 2f), barX, (getHeight() / 2f), paint);
101 | } else {
102 | int top = (getHeight() - 20) +
103 | ((byte) (Math.abs(bytes[bytePosition]) + 128)) * (getHeight() - 20) / 128;
104 | canvas.drawLine(barX, ((getHeight() + 20) - top) / 2f, barX, top, paint);
105 | }
106 | }
107 | super.onDraw(canvas);
108 | }
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/app/src/main/java/com/abh80/smartedge/plugins/MediaSession/UpdateQueueStruct.java:
--------------------------------------------------------------------------------
1 | package com.abh80.smartedge.plugins.MediaSession;
2 |
3 | import android.graphics.Bitmap;
4 |
5 | public class UpdateQueueStruct {
6 | private String artist;
7 | private String title;
8 | private Bitmap cover;
9 |
10 | public UpdateQueueStruct(String artist, String title, Bitmap cover) {
11 | this.artist = artist;
12 | this.title = title;
13 | this.cover = cover;
14 | }
15 |
16 | public String getArtist() {
17 | return artist;
18 | }
19 |
20 | public void setArtist(String artist) {
21 | this.artist = artist;
22 | }
23 |
24 | public String getTitle() {
25 | return title;
26 | }
27 |
28 | public void setTitle(String title) {
29 | this.title = title;
30 | }
31 |
32 | public Bitmap getCover() {
33 | return cover;
34 | }
35 |
36 | public void setCover(Bitmap cover) {
37 | this.cover = cover;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/main/java/com/abh80/smartedge/plugins/Notification/NotificationMeta.java:
--------------------------------------------------------------------------------
1 | package com.abh80.smartedge.plugins.Notification;
2 |
3 | import android.graphics.Bitmap;
4 | import android.graphics.drawable.Drawable;
5 | import android.graphics.drawable.Icon;
6 | import android.os.Bundle;
7 |
8 | public class NotificationMeta {
9 | private String title;
10 | private String description;
11 | private Icon icon;
12 | private Drawable icon_drawable;
13 | private Bundle all;
14 |
15 | public NotificationMeta(String title, String description, int id, Drawable icon , Bundle all) {
16 | this.title = title;
17 | this.description = description;
18 | this.icon_drawable = icon;
19 | this.id = id;
20 | this.all = all;
21 | }
22 |
23 | public Bundle getAll() {
24 | return all;
25 | }
26 |
27 | public void setAll(Bundle all) {
28 | this.all = all;
29 | }
30 |
31 | private int id;
32 |
33 | public int getId() {
34 | return id;
35 | }
36 |
37 | public void setId(int id) {
38 | this.id = id;
39 | }
40 |
41 | public Drawable getIcon_drawable() {
42 | return icon_drawable;
43 | }
44 |
45 | public void setIcon_drawable(Drawable icon_drawable) {
46 | this.icon_drawable = icon_drawable;
47 | }
48 |
49 | public String getTitle() {
50 | return title;
51 | }
52 |
53 | public void setTitle(String title) {
54 | this.title = title;
55 | }
56 |
57 | public String getDescription() {
58 | return description;
59 | }
60 |
61 | public void setDescription(String description) {
62 | this.description = description;
63 | }
64 |
65 | public Icon getIcon() {
66 | return icon;
67 | }
68 |
69 | public void setIcon(Icon icon) {
70 | this.icon = icon;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/app/src/main/java/com/abh80/smartedge/plugins/Notification/NotificationView.java:
--------------------------------------------------------------------------------
1 | package com.abh80.smartedge.plugins.Notification;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.util.AttributeSet;
6 | import android.view.View;
7 |
8 | import androidx.annotation.Nullable;
9 |
10 | public class NotificationView extends View {
11 | public NotificationView(Context context) {
12 | super(context);
13 | }
14 |
15 | public NotificationView(Context context, @Nullable AttributeSet attrs) {
16 | super(context, attrs);
17 | }
18 |
19 | public NotificationView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
20 | super(context, attrs, defStyleAttr);
21 | }
22 |
23 | public NotificationView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
24 | super(context, attrs, defStyleAttr, defStyleRes);
25 | }
26 |
27 | @Override
28 | protected void onDraw(Canvas canvas) {
29 |
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/main/java/com/abh80/smartedge/services/NotiService.java:
--------------------------------------------------------------------------------
1 | package com.abh80.smartedge.services;
2 |
3 | import android.app.Notification;
4 | import android.app.NotificationChannel;
5 | import android.app.NotificationManager;
6 | import android.content.BroadcastReceiver;
7 | import android.content.Context;
8 | import android.content.Intent;
9 | import android.content.IntentFilter;
10 | import android.service.notification.NotificationListenerService;
11 | import android.service.notification.StatusBarNotification;
12 | import android.util.Log;
13 |
14 | import java.util.ArrayList;
15 | import java.util.Arrays;
16 | import java.util.List;
17 | import java.util.Optional;
18 |
19 |
20 | public class NotiService extends NotificationListenerService {
21 |
22 | @Override
23 | public void onCreate() {
24 | super.onCreate();
25 | IntentFilter filter = new IntentFilter(getPackageName() + ".ACTION_OPEN_CLOSE");
26 | filter.addAction(getPackageName() + ".ACTION_CLOSE");
27 | registerReceiver(receiver, filter);
28 | }
29 |
30 | private final ArrayList notifications = new ArrayList<>();
31 |
32 | @Override
33 | public void onDestroy() {
34 | super.onDestroy();
35 | unregisterReceiver(receiver);
36 | }
37 |
38 | @Override
39 | public void onNotificationPosted(StatusBarNotification sbn) {
40 | super.onNotificationRemoved(sbn);
41 | Intent intent = new Intent(getPackageName() + ".NOTIFICATION_POSTED");
42 | Notification notification = sbn.getNotification();
43 | intent.putExtra("package_name", sbn.getPackageName());
44 | intent.putExtra("id", sbn.getId());
45 | intent.putExtra("time", sbn.getPostTime());
46 | intent.putExtra("icon_large", sbn.getNotification().getLargeIcon());
47 | intent.putExtra("icon_small", sbn.getNotification().getSmallIcon());
48 | intent.putExtra("category", sbn.getNotification().category);
49 | try {
50 | intent.putExtra("title", notification.extras.getString("android.title"));
51 | intent.putExtra("body", notification.extras.getString("android.text"));
52 | } catch (Exception e) {
53 | //ignore
54 | }
55 | notifications.add(sbn);
56 | sendBroadcast(intent);
57 | }
58 |
59 | @Override
60 | public void onNotificationRemoved(StatusBarNotification sbn) {
61 | super.onNotificationPosted(sbn);
62 | Intent intent = new Intent(getPackageName() + ".NOTIFICATION_REMOVED");
63 | intent.putExtra("id", sbn.getId());
64 | notifications.remove(sbn);
65 | sendBroadcast(intent);
66 | }
67 |
68 | private final BroadcastReceiver receiver = new BroadcastReceiver() {
69 | @Override
70 | public void onReceive(Context context, Intent intent) {
71 | if (intent.getAction().equals(context.getPackageName() + ".ACTION_OPEN_CLOSE")) {
72 | Optional n = notifications.stream().filter(x -> x.getId() == intent.getExtras().getInt("id")).findFirst();
73 | n.ifPresent(x -> {
74 | try {
75 | if (x.getNotification().deleteIntent != null) {
76 | x.getNotification().deleteIntent.send();
77 | } else {
78 | cancelNotification(x.getKey());
79 | }
80 | if (x.getNotification().contentIntent != null) {
81 | x.getNotification().contentIntent.send();
82 | }
83 | } catch (Exception ignored) {
84 | }
85 | });
86 | }
87 | if (intent.getAction().equals(context.getPackageName() + ".ACTION_CLOSE")) {
88 | Optional n = notifications.stream().filter(x -> x.getId() == intent.getExtras().getInt("id")).findFirst();
89 | n.ifPresent(x -> {
90 | try {
91 | if (x.getNotification().deleteIntent != null) {
92 | x.getNotification().deleteIntent.send();
93 | } else {
94 | cancelNotification(x.getKey());
95 | }
96 | } catch (Exception ignored) {
97 | }
98 | });
99 | }
100 | }
101 | };
102 | }
103 |
--------------------------------------------------------------------------------
/app/src/main/java/com/abh80/smartedge/services/UpdaterService.java:
--------------------------------------------------------------------------------
1 | package com.abh80.smartedge.services;
2 |
3 | import android.app.Notification;
4 | import android.app.NotificationChannel;
5 | import android.app.NotificationManager;
6 | import android.app.Service;
7 | import android.content.ActivityNotFoundException;
8 | import android.content.BroadcastReceiver;
9 | import android.content.Context;
10 | import android.content.Intent;
11 | import android.content.IntentFilter;
12 | import android.net.Uri;
13 | import android.os.AsyncTask;
14 | import android.os.Build;
15 | import android.os.Environment;
16 | import android.os.IBinder;
17 | import android.provider.Settings;
18 | import android.util.Log;
19 | import android.widget.Toast;
20 |
21 | import androidx.annotation.Nullable;
22 | import androidx.core.app.NotificationCompat;
23 | import androidx.core.content.FileProvider;
24 |
25 | import com.abh80.smartedge.BuildConfig;
26 | import com.abh80.smartedge.R;
27 | import com.android.volley.Request;
28 | import com.android.volley.RequestQueue;
29 | import com.android.volley.Response;
30 | import com.android.volley.VolleyError;
31 | import com.android.volley.toolbox.JsonArrayRequest;
32 | import com.android.volley.toolbox.JsonObjectRequest;
33 | import com.android.volley.toolbox.Volley;
34 |
35 | import org.json.JSONArray;
36 | import org.json.JSONException;
37 | import org.json.JSONObject;
38 |
39 | import java.io.BufferedInputStream;
40 | import java.io.File;
41 | import java.io.FileOutputStream;
42 | import java.io.InputStream;
43 | import java.io.OutputStream;
44 | import java.net.URL;
45 | import java.net.URLConnection;
46 |
47 | public class UpdaterService extends Service {
48 |
49 | @Nullable
50 | @Override
51 | public IBinder onBind(Intent intent) {
52 | return null;
53 | }
54 |
55 | private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
56 | @Override
57 | public void onReceive(Context context, Intent intent) {
58 | if (intent.getAction().equals(getPackageName() + ".START_UPDATE")) {
59 | if (download_url != null) {
60 | new DownloadFileFromURL().execute(download_url);
61 | } else {
62 | sendNotification("Cannot update app, please report the problem to developer.", NotificationManager.IMPORTANCE_HIGH, false);
63 | }
64 | }
65 | }
66 | };
67 | private String download_url;
68 |
69 | @Override
70 | public void onCreate() {
71 | super.onCreate();
72 | manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
73 | RequestQueue queue = Volley.newRequestQueue(this);
74 | sendNotification("Checking for updates", NotificationManager.IMPORTANCE_MIN, true);
75 | registerReceiver(broadcastReceiver, new IntentFilter(getPackageName() + ".START_UPDATE"));
76 | int VERSION_CODE = BuildConfig.VERSION_CODE;
77 | String baseUrl = "https://api.github.com/";
78 | JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(Request.Method.GET, baseUrl + "repos/abh80/smart-edge/releases",
79 | null, response -> {
80 | if (response.length() > 0) {
81 | try {
82 | JSONObject object = (JSONObject) response.get(0);
83 | try {
84 | if (Integer.parseInt(object.getString("tag_name")) > VERSION_CODE) {
85 | JSONArray o = object.getJSONArray("assets");
86 | download_url = ((JSONObject) o.get(0)).getString("browser_download_url");
87 | Intent intent = new Intent(getPackageName() + ".UPDATE_AVAIL");
88 | intent.putExtra("version", object.getString("name"));
89 | sendBroadcast(new Intent(intent));
90 | sendNotification("Update available", NotificationManager.IMPORTANCE_MAX, false);
91 | } else {
92 | stopSelf();
93 | }
94 | } catch (Exception e) {
95 | // do nothing lol
96 | stopSelf();
97 | }
98 |
99 | } catch (JSONException e) {
100 | e.printStackTrace();
101 | stopSelf();
102 | }
103 |
104 | } else {
105 | stopSelf();
106 | }
107 | }, error ->
108 |
109 | {
110 | });
111 | queue.add(jsonArrayRequest);
112 | }
113 |
114 | @Override
115 | public void onDestroy() {
116 | super.onDestroy();
117 | unregisterReceiver(broadcastReceiver);
118 | manager.cancel(1001);
119 | }
120 |
121 | NotificationManager manager;
122 |
123 |
124 | private void sendNotification(String text, int priority, boolean ongoing) {
125 | final String NOTIFICATION_CHANNEL_ID = getPackageName() + ".updater_channel";
126 | String channelName = "Updater Service";
127 | NotificationChannel chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_MIN);
128 | manager.createNotificationChannel(chan);
129 |
130 | NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);
131 | Notification notification = notificationBuilder.setOngoing(ongoing)
132 | .setContentTitle("Smart Edge")
133 | .setContentText(text)
134 | .setSmallIcon(R.drawable.launcher_foreground)
135 | .setPriority(priority)
136 | .setCategory(Notification.CATEGORY_SERVICE)
137 | .build();
138 | manager.notify(1001, notification);
139 | }
140 | class DownloadFileFromURL extends AsyncTask {
141 |
142 | /**
143 | * Before starting background thread Show Progress Bar Dialog
144 | */
145 | @Override
146 | protected void onPreExecute() {
147 | super.onPreExecute();
148 | sendNotification("Starting download", NotificationManager.IMPORTANCE_MIN, true);
149 | }
150 |
151 | /**
152 | * Downloading file in background thread
153 | */
154 | @Override
155 | protected String doInBackground(String... f_url) {
156 | int count;
157 | try {
158 | URL url = new URL(f_url[0]);
159 | URLConnection connection = url.openConnection();
160 | connection.connect();
161 |
162 | // this will be useful so that you can show a tipical 0-100%
163 | // progress bar
164 | int lenghtOfFile = connection.getContentLength();
165 |
166 | // download the file
167 | InputStream input = new BufferedInputStream(url.openStream(),
168 | 8192);
169 |
170 | // Output stream
171 | OutputStream output = new FileOutputStream(getExternalFilesDir(null).getAbsolutePath() + "/output.apk");
172 |
173 | byte data[] = new byte[1024];
174 |
175 | long total = 0;
176 |
177 | while ((count = input.read(data)) != -1) {
178 | total += count;
179 | // publishing the progress....
180 | // After this onProgressUpdate will be called
181 | publishProgress("" + (int) ((total * 100) / lenghtOfFile));
182 |
183 | // writing data to file
184 | output.write(data, 0, count);
185 | }
186 |
187 | // flushing output
188 | output.flush();
189 |
190 | // closing streams
191 | output.close();
192 | input.close();
193 |
194 | } catch (Exception e) {
195 | Log.e("Error: ", e.getMessage());
196 | }
197 |
198 | return null;
199 | }
200 |
201 | protected void onProgressUpdate(String... progress) {
202 | final String NOTIFICATION_CHANNEL_ID = getPackageName() + ".updater_channel";
203 | NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(UpdaterService.this, NOTIFICATION_CHANNEL_ID);
204 | notificationBuilder.setOngoing(true)
205 | .setSmallIcon(R.drawable.launcher_foreground)
206 | .setPriority(NotificationManager.IMPORTANCE_MIN)
207 | .setCategory(Notification.CATEGORY_PROGRESS)
208 | .setContentTitle("Smart Edge")
209 | .setContentText("Downloading update")
210 | .setProgress(100, Integer.parseInt(String.valueOf(progress[0])), false);
211 |
212 | Notification notification = notificationBuilder.build();
213 | manager.notify(1001, notification);
214 | }
215 |
216 | // Source for below codes : https://medium.com/@vishtech36/installing-apps-programmatically-in-android-10-7e39cfe22b86
217 | @Override
218 | protected void onPostExecute(String file_url) {
219 | String PATH = getExternalFilesDir(null).getAbsolutePath() + "/output.apk";
220 | File file = new File(PATH);
221 | if (file.exists()) {
222 | Intent intent = new Intent(Intent.ACTION_VIEW);
223 | intent.setDataAndType(uriFromFile(getApplicationContext(), new File(PATH)), "application/vnd.android.package-archive");
224 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
225 | intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
226 | try {
227 | getApplicationContext().startActivity(intent);
228 | } catch (ActivityNotFoundException e) {
229 | e.printStackTrace();
230 | Log.e("TAG", "Error in opening the file!");
231 | }
232 | } else {
233 | Toast.makeText(getApplicationContext(), "installing", Toast.LENGTH_LONG).show();
234 | }
235 |
236 |
237 | UpdaterService.this.
238 |
239 | stopSelf();
240 | }
241 |
242 | Uri uriFromFile(Context context, File file) {
243 | return FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", file);
244 |
245 | }
246 | }
247 | }
248 |
--------------------------------------------------------------------------------
/app/src/main/java/com/abh80/smartedge/utils/CallBack.java:
--------------------------------------------------------------------------------
1 | package com.abh80.smartedge.utils;
2 |
3 | public class CallBack {
4 |
5 | public void onFinish(){
6 | // do something
7 | }
8 | public void onChange(float p){
9 |
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/app/src/main/java/com/abh80/smartedge/utils/NotificationAppMeta.java:
--------------------------------------------------------------------------------
1 | package com.abh80.smartedge.utils;
2 |
3 | import android.graphics.drawable.Drawable;
4 |
5 | public class NotificationAppMeta {
6 | public String name;
7 | public String package_name;
8 | public Drawable app_icon;
9 | public boolean enabled;
10 |
11 | public NotificationAppMeta(String name, String package_name, Drawable app_icon) {
12 | this.name = name;
13 | this.package_name = package_name;
14 | this.app_icon = app_icon;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/java/com/abh80/smartedge/utils/NotificationHolderClass.java:
--------------------------------------------------------------------------------
1 | package com.abh80.smartedge.utils;
2 |
3 | import android.service.notification.StatusBarNotification;
4 |
5 | import java.io.Serializable;
6 |
7 | public class NotificationHolderClass implements Serializable {
8 | public StatusBarNotification notification;
9 |
10 | public NotificationHolderClass(StatusBarNotification notification) {
11 | this.notification = notification;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/abh80/smartedge/utils/SettingStruct.java:
--------------------------------------------------------------------------------
1 | package com.abh80.smartedge.utils;
2 |
3 | import android.content.Context;
4 |
5 | public class SettingStruct {
6 | public static int TYPE_TOGGLE = 1;
7 | public static int TYPE_CUSTOM = 2;
8 |
9 | public String text;
10 | public String category;
11 | public int type;
12 |
13 | public SettingStruct(String text, String cat) {
14 | this.text = text;
15 | this.category = cat;
16 | type = TYPE_TOGGLE;
17 | }
18 |
19 | public SettingStruct(String text, String category, int type) {
20 | this.text = text;
21 | this.category = category;
22 | this.type = type;
23 | }
24 |
25 | public void onCheckChanged(boolean checked , Context ctx) {
26 | }
27 |
28 | public void onClick(Context ctx) {
29 | }
30 |
31 | public boolean onAttach(Context ctx) {
32 | return false;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/app/src/main/java/com/abh80/smartedge/utils/adapters/NotificationManageAppsAdapter.java:
--------------------------------------------------------------------------------
1 | package com.abh80.smartedge.utils.adapters;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import android.util.Log;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.CompoundButton;
10 | import android.widget.TextView;
11 |
12 | import androidx.annotation.NonNull;
13 | import androidx.recyclerview.widget.RecyclerView;
14 |
15 | import com.abh80.smartedge.R;
16 | import com.abh80.smartedge.utils.NotificationAppMeta;
17 | import com.google.android.material.imageview.ShapeableImageView;
18 | import com.google.android.material.materialswitch.MaterialSwitch;
19 |
20 | import org.apache.commons.lang3.StringUtils;
21 |
22 | import java.util.ArrayList;
23 | import java.util.Arrays;
24 | import java.util.List;
25 |
26 | public class NotificationManageAppsAdapter extends RecyclerView.Adapter {
27 | public ArrayList apps;
28 | private SharedPreferences sharedPreferences;
29 |
30 | public NotificationManageAppsAdapter(SharedPreferences sharedPreferences, ArrayList apps) {
31 | this.apps = apps;
32 | this.sharedPreferences = sharedPreferences;
33 | }
34 |
35 | @NonNull
36 | @Override
37 | public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
38 | return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.single_notification_layout_app, parent, false));
39 | }
40 |
41 | @Override
42 | public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
43 | holder.imageView.setImageDrawable(apps.get(position).app_icon);
44 | holder.name.setText(apps.get(position).name);
45 | holder.switchBtn.setChecked(apps.get(position).enabled);
46 | holder.switchBtn.setOnClickListener(l -> {
47 | NotificationAppMeta app = apps.get(position);
48 | app.enabled = holder.switchBtn.isChecked();
49 | holder.switchBtn.setChecked(holder.switchBtn.isChecked());
50 | ArrayList p = parseEnabledApps(sharedPreferences.getString("notifications_apps", ""));
51 | if (app.enabled) {
52 | p.add(app.package_name);
53 | } else {
54 | p.remove(app.package_name);
55 | }
56 | sharedPreferences.edit().putString("notifications_apps", StringUtils.join(p, ",")).apply();
57 | });
58 | }
59 |
60 | public static ArrayList parseEnabledApps(String s) {
61 | return new ArrayList<>(Arrays.asList(s.split(",")));
62 | }
63 |
64 | @Override
65 | public int getItemCount() {
66 | return apps.size();
67 | }
68 |
69 | public static class ViewHolder extends RecyclerView.ViewHolder {
70 | public TextView name;
71 | public MaterialSwitch switchBtn;
72 | public ShapeableImageView imageView;
73 |
74 | public ViewHolder(@NonNull View itemView) {
75 | super(itemView);
76 | name = itemView.findViewById(R.id.app_title);
77 | switchBtn = itemView.findViewById(R.id.app_switch);
78 | imageView = itemView.findViewById(R.id.app_image);
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/app/src/main/java/com/abh80/smartedge/utils/adapters/NotificationViewPagerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.abh80.smartedge.utils.adapters;
2 |
3 | import android.content.Context;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.TextView;
8 |
9 | import androidx.annotation.NonNull;
10 | import androidx.viewpager.widget.PagerAdapter;
11 | import androidx.viewpager.widget.ViewPager;
12 |
13 | import com.abh80.smartedge.R;
14 | import com.abh80.smartedge.plugins.Notification.NotificationMeta;
15 | import com.abh80.smartedge.services.OverlayService;
16 |
17 | import org.ocpsoft.prettytime.PrettyTime;
18 |
19 | import java.util.ArrayList;
20 | import java.util.Date;
21 |
22 | public class NotificationViewPagerAdapter extends PagerAdapter {
23 | private ArrayList notifications;
24 | private OverlayService ctx;
25 |
26 | public NotificationViewPagerAdapter(ArrayList metas, OverlayService context) {
27 | ctx = context;
28 | notifications = metas;
29 | }
30 |
31 | public void updateNotifications(ArrayList metas) {
32 | notifications = metas;
33 | }
34 |
35 | @NonNull
36 | @Override
37 | public Object instantiateItem(@NonNull ViewGroup container, int position) {
38 | NotificationMeta meta = notifications.get(position);
39 | View mView = LayoutInflater.from(container.getContext()).inflate(R.layout.single_notification, null);
40 | ((TextView) mView.findViewById(R.id.title)).setText(meta.getTitle());
41 | ((TextView) mView.findViewById(R.id.text_description)).setText(meta.getDescription());
42 | StringBuilder stringBuilder = new StringBuilder();
43 | String name = meta.getAll().getString("name");
44 | if (name != null) stringBuilder.append(name).append(" • ");
45 | long since = meta.getAll().getLong("time");
46 | PrettyTime p = new PrettyTime();
47 | stringBuilder.append(p.format(new Date(since)));
48 | ((TextView) mView.findViewById(R.id.author)).setText(stringBuilder.toString());
49 | int value = ctx.getAttr(androidx.appcompat.R.attr.colorPrimary);
50 | ((TextView) mView.findViewById(R.id.author)).setTextColor(value);
51 | mView.findViewById(R.id.title).setSelected(true);
52 | mView.findViewById(R.id.text_description).setSelected(true);
53 | ((TextView) mView.findViewById(R.id.title)).setTextColor(ctx.textColor);
54 | ((TextView) mView.findViewById(R.id.text_description)).setTextColor(ctx.textColor);
55 | container.addView(mView);
56 | mView.setTag("mv_" + position);
57 | return mView;
58 | }
59 |
60 | @Override
61 | public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
62 | container.removeView((View) object);
63 | }
64 |
65 | @Override
66 | public int getItemPosition(@NonNull Object object) {
67 | return POSITION_NONE;
68 | }
69 |
70 | @Override
71 | public int getCount() {
72 | return notifications.size();
73 | }
74 |
75 | @Override
76 | public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
77 | return view == object;
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/app/src/main/java/com/abh80/smartedge/utils/adapters/RecylerViewSettingsAdapter.java:
--------------------------------------------------------------------------------
1 | package com.abh80.smartedge.utils.adapters;
2 |
3 | import android.content.Context;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.TextView;
8 |
9 | import androidx.annotation.NonNull;
10 | import androidx.recyclerview.widget.RecyclerView;
11 |
12 | import com.abh80.smartedge.R;
13 | import com.abh80.smartedge.utils.SettingStruct;
14 | import com.google.android.material.materialswitch.MaterialSwitch;
15 |
16 | import java.util.ArrayList;
17 |
18 | public class RecylerViewSettingsAdapter extends RecyclerView.Adapter {
19 | private final Context context;
20 | private final ArrayList settings;
21 |
22 | public RecylerViewSettingsAdapter(Context context, ArrayList settings) {
23 | this.context = context;
24 | this.settings = settings;
25 | settings.add(0, null);
26 | }
27 |
28 | @NonNull
29 | @Override
30 | public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
31 | View itemView;
32 | if (viewType == SettingStruct.TYPE_TOGGLE) {
33 | itemView = LayoutInflater.from(context).inflate(R.layout.toggle_setting_layout, parent, false);
34 | } else if (viewType == SettingStruct.TYPE_CUSTOM) {
35 | itemView = LayoutInflater.from(context).inflate(R.layout.setting_custom_layout, parent, false);
36 | } else {
37 | itemView = LayoutInflater.from(context).inflate(R.layout.toggle_setting_null_layout, parent, false);
38 | }
39 | return new ViewHolder(itemView, viewType);
40 | }
41 |
42 | @Override
43 | public int getItemViewType(final int position) {
44 | if (settings.get(position) == null) return 0;
45 | return settings.get(position).type;
46 | }
47 |
48 | @Override
49 | public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
50 | if (!holder.isItem) return;
51 | holder.textView.setText(settings.get(position).text);
52 | if (holder.ViewType == SettingStruct.TYPE_CUSTOM) {
53 | holder.itemView.setOnClickListener(l -> settings.get(position).onClick(context));
54 | }
55 | if (holder.ViewType == SettingStruct.TYPE_TOGGLE) {
56 | holder.switchBtn.setOnCheckedChangeListener((compoundButton, b) -> {
57 | settings.get(position).onCheckChanged(b, context);
58 | });
59 | holder.switchBtn.setChecked(settings.get(position).onAttach(context));
60 | }
61 | }
62 |
63 | @Override
64 | public int getItemCount() {
65 | return settings.size();
66 | }
67 |
68 | public static class ViewHolder extends RecyclerView.ViewHolder {
69 | public TextView textView;
70 | public MaterialSwitch switchBtn;
71 | public boolean isItem;
72 | public View itemView;
73 | public int ViewType;
74 |
75 | public ViewHolder(@NonNull View itemView, int itemViewType) {
76 | super(itemView);
77 | this.itemView = itemView;
78 | ViewType = itemViewType;
79 | isItem = itemViewType != 0;
80 | if (!isItem) {
81 | textView = itemView.findViewById(R.id.cat_text);
82 | return;
83 | }
84 | textView = itemView.findViewById(R.id.enable_text);
85 | if (itemViewType == SettingStruct.TYPE_TOGGLE) {
86 | switchBtn = itemView.findViewById(R.id.enable_switch2);
87 | }
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/app/src/main/java/com/abh80/smartedge/views/BatteryImageView.java:
--------------------------------------------------------------------------------
1 | package com.abh80.smartedge.views;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.graphics.Canvas;
6 | import android.graphics.Color;
7 | import android.graphics.Paint;
8 | import android.graphics.Path;
9 | import android.graphics.RectF;
10 | import android.util.AttributeSet;
11 | import android.util.Log;
12 | import android.view.View;
13 |
14 | import androidx.annotation.Nullable;
15 |
16 | public class BatteryImageView extends View {
17 | public BatteryImageView(Context context) {
18 | super(context);
19 | init();
20 | }
21 |
22 | private void init() {
23 | paint = new Paint() {
24 | {
25 | setAntiAlias(true);
26 | setColor(Color.GREEN);
27 | setStrokeWidth(8);
28 | setStyle(Style.STROKE);
29 | setStrokeJoin(Join.MITER);
30 | setDither(true);
31 | }
32 | };
33 | }
34 |
35 | public BatteryImageView(Context context, @Nullable AttributeSet attrs) {
36 | super(context, attrs);
37 | init();
38 | }
39 |
40 | public BatteryImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
41 | super(context, attrs, defStyleAttr);
42 | init();
43 | }
44 |
45 | Paint paint;
46 | private float batterPercent;
47 |
48 | public void updateBatteryPercent(float p) {
49 | batterPercent = p;
50 | invalidate();
51 | }
52 |
53 | public void setStrokeColor(int color) {
54 | if (paint != null) paint.setColor(color);
55 | invalidate();
56 | }
57 |
58 | @SuppressLint("DrawAllocation")
59 | @Override
60 | protected void onDraw(Canvas canvas) {
61 | super.onDraw(canvas);
62 | if (paint == null) {
63 | init();
64 | }
65 | float margin = 5;
66 | RectF rectangle = new RectF(margin, margin, getWidth() - margin, getHeight() - margin);
67 | canvas.drawArc(rectangle, 270f, (batterPercent / 100f) * 360f, false, paint);
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/app/src/main/java/com/abh80/smartedge/views/ViewPagerOnClickable.java:
--------------------------------------------------------------------------------
1 | package com.abh80.smartedge.views;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.MotionEvent;
6 |
7 | import androidx.annotation.NonNull;
8 | import androidx.annotation.Nullable;
9 | import androidx.viewpager.widget.ViewPager;
10 |
11 | public class ViewPagerOnClickable extends ViewPager {
12 | public ViewPagerOnClickable(@NonNull Context context) {
13 | super(context);
14 | }
15 |
16 | public ViewPagerOnClickable(@NonNull Context context, @Nullable AttributeSet attrs) {
17 | super(context, attrs);
18 | }
19 |
20 | @Override
21 | public boolean onInterceptTouchEvent(MotionEvent ev) {
22 | onTouchEvent(ev);
23 | return false;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/avd_pause_to_play.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
11 |
15 |
16 |
17 |
18 |
19 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/avd_play_to_pause.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
11 |
15 |
16 |
17 |
18 |
19 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/fast_forward.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/fast_rewind.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abh80/smart-edge/0a4dcd81506662ecd52c91b3a419f888446e4baa/app/src/main/res/drawable-v24/launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/pause.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/play.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/custom_progress_bar_horizontal.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | -
12 |
14 |
15 | -
16 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/default_dot.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_add_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_arrow_back_ios_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_fast_forward_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_fast_rewind_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_message_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_open_in_new_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_pause_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_play_arrow_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_remove_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_outline_refresh_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ripple.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/rounded_corner.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/rounded_corner_setting_bottom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/rounded_corner_setting_top.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/selected_dot.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/tab_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
14 |
15 |
25 |
26 |
32 |
33 |
41 |
42 |
43 |
44 |
51 |
52 |
53 |
54 |
57 |
58 |
66 |
67 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_permission.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
18 |
19 |
29 |
30 |
31 |
41 |
42 |
43 |
47 |
48 |
54 |
55 |
59 |
60 |
68 |
77 |
78 |
79 |
80 |
81 |
82 |
93 |
94 |
99 |
100 |
106 |
107 |
111 |
112 |
120 |
129 |
130 |
131 |
132 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/appearence_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
14 |
15 |
19 |
20 |
21 |
28 |
29 |
30 |
33 |
34 |
35 |
41 |
42 |
43 |
44 |
45 |
48 |
49 |
57 |
58 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/battery_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
19 |
20 |
28 |
29 |
30 |
42 |
43 |
52 |
53 |
54 |
55 |
56 |
64 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/manage_notification_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
15 |
16 |
17 |
18 |
19 |
22 |
23 |
31 |
32 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/media_session_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
24 |
25 |
26 |
36 |
37 |
44 |
45 |
46 |
47 |
48 |
55 |
56 |
65 |
66 |
70 |
71 |
87 |
88 |
89 |
93 |
94 |
111 |
112 |
113 |
114 |
124 |
125 |
141 |
142 |
153 |
154 |
162 |
163 |
172 |
173 |
182 |
183 |
192 |
193 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/notification_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
19 |
20 |
30 |
31 |
32 |
44 |
45 |
56 |
57 |
58 |
59 |
60 |
68 |
69 |
80 |
81 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/overlay_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/setting_custom_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
22 |
23 |
24 |
34 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/single_notification.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
12 |
13 |
28 |
29 |
30 |
31 |
34 |
35 |
51 |
52 |
53 |
57 |
58 |
71 |
72 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/single_notification_layout_app.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
13 |
22 |
23 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/toggle_setting_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
19 |
20 |
21 |
27 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/toggle_setting_null_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/notifications_top_bar_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abh80/smart-edge/0a4dcd81506662ecd52c91b3a419f888446e4baa/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abh80/smart-edge/0a4dcd81506662ecd52c91b3a419f888446e4baa/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abh80/smart-edge/0a4dcd81506662ecd52c91b3a419f888446e4baa/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abh80/smart-edge/0a4dcd81506662ecd52c91b3a419f888446e4baa/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abh80/smart-edge/0a4dcd81506662ecd52c91b3a419f888446e4baa/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abh80/smart-edge/0a4dcd81506662ecd52c91b3a419f888446e4baa/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abh80/smart-edge/0a4dcd81506662ecd52c91b3a419f888446e4baa/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abh80/smart-edge/0a4dcd81506662ecd52c91b3a419f888446e4baa/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abh80/smart-edge/0a4dcd81506662ecd52c91b3a419f888446e4baa/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abh80/smart-edge/0a4dcd81506662ecd52c91b3a419f888446e4baa/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF03DAC5
7 | #FF018786
8 | #FF000000
9 | #FFFFFFFF
10 | #70FFFFFF
11 | #d9d3d3
12 | #00000000
13 | #6750A4
14 | #6750A4
15 | #6750A4
16 | #410E0B
17 | #FFFFFF
18 | #F9DEDC
19 | #31111D
20 | #FFFFFF
21 | #FFD8E4
22 | #7D5260
23 | #000000
24 | #B3261E
25 | #79747E
26 | #1C1B1F
27 | #FFFBFE
28 | #F4EFF4
29 | #313033
30 | #49454F
31 | #1C1B1F
32 | #E7E0EC
33 | #FFFBFE
34 | #1D192B
35 | #FFFFFF
36 | #E8DEF8
37 | #625B71
38 | #D0BCFF
39 | #21005D
40 | #FFFFFF
41 | #EADDFF
42 | #6750A4
43 | #D0BCFF
44 | #D0BCFF
45 | #F2B8B5
46 | #601410
47 | #8C1D18
48 | #FFD8E4
49 | #492532
50 | #633B48
51 | #EFB8C8
52 | #000000
53 | #F2B8B5
54 | #938F99
55 | #E6E1E5
56 | #1C1B1F
57 | #313033
58 | #E6E1E5
59 | #CAC4D0
60 | #E6E1E5
61 | #49454F
62 | #1C1B1F
63 | #E8DEF8
64 | #332D41
65 | #4A4458
66 | #CCC2DC
67 | #6750A4
68 | #EADDFF
69 | #381E72
70 | #4F378B
71 | #D0BCFF
72 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 100dp
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Smart Edge
3 | cover
4 | pause/play
5 | next
6 | back
7 | Welcome
8 | To get started, the app needs some required permissions
9 | Draw over other apps
10 | Notification Access
11 | Record Audio from apps
12 | Enable Smart Edge
13 | Enable Hardware Acceleration
14 | Turn on to let the app draw over status bar
15 | X offset
16 | Y offset
17 | Height of overlay when shrinked
18 | Minimum Width of overlay when closed
19 | Space between icons when overlay is shrinked
20 | Reset
21 | Select applications to allow
22 | all
23 | Needed to show notifications and media sessions
24 | Needed to show song visualizer. Never to be used for recording mic audio
25 | Select color to apply to background
26 | Color (hex)
27 | Apply
28 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
9 |
13 |
17 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/global_action_bar_service.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/overlay_layout_scene.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
11 |
12 |
13 |
14 |
15 |
16 |
23 |
24 |
25 |
26 |
33 |
34 |
35 |
42 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/provider_paths.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/test/java/com/abh80/smartedge/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.abh80.smartedge;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | plugins {
3 | id 'com.android.application' version '7.2.2' apply false
4 | id 'com.android.library' version '7.2.2' apply false
5 | }
6 |
7 | task clean(type: Delete) {
8 | delete rootProject.buildDir
9 | }
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/20202.txt:
--------------------------------------------------------------------------------
1 | * Added fine tuning for overlay position.
2 | * Fixed error during screen off.
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/20203.txt:
--------------------------------------------------------------------------------
1 | * New bug fixes
2 | * Improved stabilization
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/20204.txt:
--------------------------------------------------------------------------------
1 | * Attempt to fix #59
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/full_description.txt:
--------------------------------------------------------------------------------
1 | Smart edge allows you to add a overlay which expands and shows you required information at ease
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abh80/smart-edge/0a4dcd81506662ecd52c91b3a419f888446e4baa/fastlane/metadata/android/en-US/images/icon.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abh80/smart-edge/0a4dcd81506662ecd52c91b3a419f888446e4baa/fastlane/metadata/android/en-US/images/phoneScreenshots/screenshot.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/short_description.txt:
--------------------------------------------------------------------------------
1 | Android alternative for Dynamic Island
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Enables namespacing of each library's R class so that its R class includes only the
19 | # resources declared in the library itself and none from the library's dependencies,
20 | # thereby reducing the size of the R class for that library
21 | android.nonTransitiveRClass=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abh80/smart-edge/0a4dcd81506662ecd52c91b3a419f888446e4baa/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Sep 10 15:26:42 IST 2022
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "smart-edge",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "repository": "https://github.com/abh80/smart-edge.git",
6 | "author": "abh80",
7 | "license": "MIT",
8 | "dependencies": {
9 | "@actions/core": "^1.9.1",
10 | "@actions/github": "^5.1.0"
11 | },
12 | "devDependencies": {
13 | "@types/node": "^18.7.23"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/scripts/release.js:
--------------------------------------------------------------------------------
1 | const core = require("@actions/core");
2 | const fs = require("fs");
3 | const github = require("@actions/github");
4 | const gradleBuild = fs.readFileSync(process.cwd() + "/app/build.gradle", {
5 | encoding: "ascii",
6 | });
7 | const versionCode = gradleBuild
8 | .split("\n")
9 | .find((x) => x.includes("versionCode"))
10 | .trim()
11 | .replace("versionCode", "")
12 | .replace(/"/g, "")
13 | .trim();
14 | const versionName = gradleBuild
15 | .split("\n")
16 | .find((x) => x.includes("versionName"))
17 | .trim()
18 | .replace("versionName", "")
19 | .replace(/"/g, "")
20 | .trim();
21 | (async () => {
22 | const TOKEN = process.env["TOKEN"];
23 | if (!TOKEN) return core.setFailed("No token was provided, exiting...");
24 | const octokit = github.getOctokit(TOKEN);
25 | let text = "🎉 v" + versionName + " Released!";
26 | const build_path =
27 | process.cwd() + "/app/build/outputs/apk/github/app-github.apk";
28 | const changelogFile = process.cwd() + "/fastlane/metadata/android/en-US/changelogs/" + versionCode + ".txt";
29 | if (fs.existsSync(changelogFile)) {
30 | text += "\n\n";
31 | text += "# Changelogs";
32 | text += "\n"
33 | text += fs.readFileSync(changelogFile, {encoding: "ascii"});
34 | }
35 | const data = await octokit.rest.repos.createRelease({
36 | owner: "abh80",
37 | repo: "smart-edge",
38 | tag_name: versionCode,
39 | name: "v" + versionName,
40 | body: text,
41 | });
42 | const fdata = await octokit.rest.repos.uploadReleaseAsset({
43 | owner: "abh80",
44 | repo: "smart-edge",
45 | name: "release.apk",
46 | body: "Automatic Build",
47 | data: fs.readFileSync(build_path),
48 | release_id: data.data.id,
49 | });
50 | const base_md = [
51 | `# Smart Edge (Early Access) [](https://github.com/abh80/smart-edge/actions/workflows/release.yml)
52 | Alternative to dynamic island for android.`,
53 | `# Donations
54 | Help support the project by donating ❤️
55 |
56 |
57 |
58 | `,
59 | ];
60 | const downloadsmd = `# Downloads
61 |
62 | [](${fdata.data.browser_download_url})`;
63 | const previewsMd = [`\n# Previews`];
64 | const screenshots = fs.readdirSync(
65 | process.cwd() + "/fastlane/metadata/android/en-US/images/phoneScreenshots"
66 | );
67 | screenshots.forEach((image) => {
68 | previewsMd.push(
69 | `
`
70 | );
71 | });
72 | fs.writeFileSync(
73 | process.cwd() + "/README.md",
74 | [
75 | base_md[0],
76 | downloadsmd,
77 | base_md[1],
78 | previewsMd.join("\n"),
79 | ].join("\n")
80 | );
81 | core.setOutput("Successfully published apk!");
82 | })();
83 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | gradlePluginPortal()
4 | google()
5 | mavenCentral()
6 | }
7 | }
8 | dependencyResolutionManagement {
9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
10 | repositories {
11 | google()
12 | mavenCentral()
13 | }
14 | }
15 | rootProject.name = "Smart Edge"
16 | include ':app'
17 |
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | "@actions/core@^1.9.1":
6 | "integrity" "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA=="
7 | "resolved" "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz"
8 | "version" "1.9.1"
9 | dependencies:
10 | "@actions/http-client" "^2.0.1"
11 | "uuid" "^8.3.2"
12 |
13 | "@actions/github@^5.1.0":
14 | "integrity" "sha512-tuI80F7JQIhg77ZTTgUAPpVD7ZnP9oHSPN8xw7LOwtA4vEMbAjWJNbmLBfV7xua7r016GyjzWLuec5cs8f/a8A=="
15 | "resolved" "https://registry.npmjs.org/@actions/github/-/github-5.1.0.tgz"
16 | "version" "5.1.0"
17 | dependencies:
18 | "@actions/http-client" "^2.0.1"
19 | "@octokit/core" "^3.6.0"
20 | "@octokit/plugin-paginate-rest" "^2.17.0"
21 | "@octokit/plugin-rest-endpoint-methods" "^5.13.0"
22 |
23 | "@actions/http-client@^2.0.1":
24 | "integrity" "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw=="
25 | "resolved" "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz"
26 | "version" "2.0.1"
27 | dependencies:
28 | "tunnel" "^0.0.6"
29 |
30 | "@octokit/auth-token@^2.4.4":
31 | "integrity" "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g=="
32 | "resolved" "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz"
33 | "version" "2.5.0"
34 | dependencies:
35 | "@octokit/types" "^6.0.3"
36 |
37 | "@octokit/core@^3.6.0", "@octokit/core@>=2", "@octokit/core@>=3":
38 | "integrity" "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q=="
39 | "resolved" "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz"
40 | "version" "3.6.0"
41 | dependencies:
42 | "@octokit/auth-token" "^2.4.4"
43 | "@octokit/graphql" "^4.5.8"
44 | "@octokit/request" "^5.6.3"
45 | "@octokit/request-error" "^2.0.5"
46 | "@octokit/types" "^6.0.3"
47 | "before-after-hook" "^2.2.0"
48 | "universal-user-agent" "^6.0.0"
49 |
50 | "@octokit/endpoint@^6.0.1":
51 | "integrity" "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA=="
52 | "resolved" "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz"
53 | "version" "6.0.12"
54 | dependencies:
55 | "@octokit/types" "^6.0.3"
56 | "is-plain-object" "^5.0.0"
57 | "universal-user-agent" "^6.0.0"
58 |
59 | "@octokit/graphql@^4.5.8":
60 | "integrity" "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg=="
61 | "resolved" "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz"
62 | "version" "4.8.0"
63 | dependencies:
64 | "@octokit/request" "^5.6.0"
65 | "@octokit/types" "^6.0.3"
66 | "universal-user-agent" "^6.0.0"
67 |
68 | "@octokit/openapi-types@^12.11.0":
69 | "integrity" "sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ=="
70 | "resolved" "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.11.0.tgz"
71 | "version" "12.11.0"
72 |
73 | "@octokit/plugin-paginate-rest@^2.17.0":
74 | "integrity" "sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw=="
75 | "resolved" "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz"
76 | "version" "2.21.3"
77 | dependencies:
78 | "@octokit/types" "^6.40.0"
79 |
80 | "@octokit/plugin-rest-endpoint-methods@^5.13.0":
81 | "integrity" "sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw=="
82 | "resolved" "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz"
83 | "version" "5.16.2"
84 | dependencies:
85 | "@octokit/types" "^6.39.0"
86 | "deprecation" "^2.3.1"
87 |
88 | "@octokit/request-error@^2.0.5", "@octokit/request-error@^2.1.0":
89 | "integrity" "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg=="
90 | "resolved" "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz"
91 | "version" "2.1.0"
92 | dependencies:
93 | "@octokit/types" "^6.0.3"
94 | "deprecation" "^2.0.0"
95 | "once" "^1.4.0"
96 |
97 | "@octokit/request@^5.6.0", "@octokit/request@^5.6.3":
98 | "integrity" "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A=="
99 | "resolved" "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz"
100 | "version" "5.6.3"
101 | dependencies:
102 | "@octokit/endpoint" "^6.0.1"
103 | "@octokit/request-error" "^2.1.0"
104 | "@octokit/types" "^6.16.1"
105 | "is-plain-object" "^5.0.0"
106 | "node-fetch" "^2.6.7"
107 | "universal-user-agent" "^6.0.0"
108 |
109 | "@octokit/types@^6.0.3", "@octokit/types@^6.16.1", "@octokit/types@^6.39.0", "@octokit/types@^6.40.0":
110 | "integrity" "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg=="
111 | "resolved" "https://registry.npmjs.org/@octokit/types/-/types-6.41.0.tgz"
112 | "version" "6.41.0"
113 | dependencies:
114 | "@octokit/openapi-types" "^12.11.0"
115 |
116 | "@types/node@^18.7.23":
117 | "integrity" "sha512-DWNcCHolDq0ZKGizjx2DZjR/PqsYwAcYUJmfMWqtVU2MBMG5Mo+xFZrhGId5r/O5HOuMPyQEcM6KUBp5lBZZBg=="
118 | "resolved" "https://registry.npmjs.org/@types/node/-/node-18.7.23.tgz"
119 | "version" "18.7.23"
120 |
121 | "before-after-hook@^2.2.0":
122 | "integrity" "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ=="
123 | "resolved" "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz"
124 | "version" "2.2.2"
125 |
126 | "deprecation@^2.0.0", "deprecation@^2.3.1":
127 | "integrity" "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
128 | "resolved" "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz"
129 | "version" "2.3.1"
130 |
131 | "is-plain-object@^5.0.0":
132 | "integrity" "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="
133 | "resolved" "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz"
134 | "version" "5.0.0"
135 |
136 | "node-fetch@^2.6.7":
137 | "integrity" "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ=="
138 | "resolved" "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz"
139 | "version" "2.6.7"
140 | dependencies:
141 | "whatwg-url" "^5.0.0"
142 |
143 | "once@^1.4.0":
144 | "integrity" "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="
145 | "resolved" "https://registry.npmjs.org/once/-/once-1.4.0.tgz"
146 | "version" "1.4.0"
147 | dependencies:
148 | "wrappy" "1"
149 |
150 | "tr46@~0.0.3":
151 | "integrity" "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
152 | "resolved" "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz"
153 | "version" "0.0.3"
154 |
155 | "tunnel@^0.0.6":
156 | "integrity" "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
157 | "resolved" "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz"
158 | "version" "0.0.6"
159 |
160 | "universal-user-agent@^6.0.0":
161 | "integrity" "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w=="
162 | "resolved" "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz"
163 | "version" "6.0.0"
164 |
165 | "uuid@^8.3.2":
166 | "integrity" "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
167 | "resolved" "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz"
168 | "version" "8.3.2"
169 |
170 | "webidl-conversions@^3.0.0":
171 | "integrity" "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
172 | "resolved" "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz"
173 | "version" "3.0.1"
174 |
175 | "whatwg-url@^5.0.0":
176 | "integrity" "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="
177 | "resolved" "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz"
178 | "version" "5.0.0"
179 | dependencies:
180 | "tr46" "~0.0.3"
181 | "webidl-conversions" "^3.0.0"
182 |
183 | "wrappy@1":
184 | "integrity" "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
185 | "resolved" "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"
186 | "version" "1.0.2"
187 |
--------------------------------------------------------------------------------