io.appium.settings 3.0.1 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -6
- package/apks/settings_apk-debug.apk +0 -0
- package/app/build.gradle +2 -2
- package/app/src/main/AndroidManifest.xml +4 -0
- package/app/src/main/java/io/appium/settings/LocationService.java +15 -2
- package/app/src/main/java/io/appium/settings/Settings.java +2 -0
- package/app/src/main/java/io/appium/settings/handlers/LocaleSettingHandler.java +1 -0
- package/app/src/main/java/io/appium/settings/location/LocationFactory.java +12 -1
- package/app/src/main/java/io/appium/settings/receivers/LocationInfoReceiver.java +1 -1
- package/app/src/main/java/io/appium/settings/receivers/SmsReader.java +113 -0
- package/app/src/main/java/io/appium/settings/receivers/UnpairBluetoothDevicesReceiver.java +4 -3
- package/build.gradle +1 -1
- package/gradle/wrapper/gradle-wrapper.properties +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# Settings
|
|
2
2
|
|
|
3
|
-
[](https://greenkeeper.io/)
|
|
4
|
-
|
|
5
3
|
Toggle settings in Android device or emulator.
|
|
6
4
|
|
|
7
5
|
A small and simple Android application that deals with the system settings. Then the application shuts down.
|
|
@@ -171,7 +169,7 @@ adb shell ime set io.appium.settings/.UnicodeIME
|
|
|
171
169
|
This action allows to retrieve the text content of the current clipboard
|
|
172
170
|
as base64-encoded string.
|
|
173
171
|
An empty string is returned if the clipboard cannot be retrieved
|
|
174
|
-
or the clipboard is empty.
|
|
172
|
+
or the clipboard is empty.
|
|
175
173
|
Remember, that since Android Q the clipboard content can only be retrieved if
|
|
176
174
|
the requester application is set as the default IME in the system:
|
|
177
175
|
|
|
@@ -186,8 +184,8 @@ adb shell ime set com.google.android.inputmethod.latin/com.android.inputmethod.l
|
|
|
186
184
|
## Notifications
|
|
187
185
|
|
|
188
186
|
Since version 2.16.0 Appium Settings supports retrieval of system notifications.
|
|
189
|
-
You need to manually switch the corresponding security switcher next to `Appium Settings`
|
|
190
|
-
application name in `Settings->Notification Access` (the path to this page under Settings
|
|
187
|
+
You need to manually switch the corresponding security switcher next to `Appium Settings`
|
|
188
|
+
application name in `Settings->Notification Access` (the path to this page under Settings
|
|
191
189
|
may vary depending on Android version and the device model)
|
|
192
190
|
in order to make this feature available. The next step would be to send the following broadcast command:
|
|
193
191
|
```bash
|
|
@@ -196,7 +194,7 @@ $ adb shell am broadcast -a io.appium.settings.notifications
|
|
|
196
194
|
The notifications listener service is running in the background and collects
|
|
197
195
|
all the active and newly created notifications into the internal buffer with maximum
|
|
198
196
|
size of `100`. The collected data (e.g. the properties and texts of each notification)
|
|
199
|
-
is returned as JSON-formatted string. An error description string is returned instead if the
|
|
197
|
+
is returned as JSON-formatted string. An error description string is returned instead if the
|
|
200
198
|
notifications list cannot be retrieved.
|
|
201
199
|
The example of the resulting data:
|
|
202
200
|
```json
|
|
@@ -234,6 +232,54 @@ and https://developer.android.com/reference/android/app/Notification.html
|
|
|
234
232
|
for more information on available notification properties and their values.
|
|
235
233
|
|
|
236
234
|
|
|
235
|
+
## SMS
|
|
236
|
+
|
|
237
|
+
Since version 3.1 Appium Settings supports retrieval of SMS messages.
|
|
238
|
+
Make sure the corresponding permission has been granted to the app
|
|
239
|
+
in order to make this feature available. The next step would be to send
|
|
240
|
+
the following broadcast command:
|
|
241
|
+
```bash
|
|
242
|
+
$ adb shell am broadcast -a io.appium.settings.sms.read --es max 10
|
|
243
|
+
```
|
|
244
|
+
In this example the SMS reader broadcast receiver would retrieve
|
|
245
|
+
the properties of `10 recent` incoming SMS messages. By default the limit
|
|
246
|
+
is set to `100`. The collected data (e.g. the properties and texts of each SMS)
|
|
247
|
+
is returned as JSON-formatted string. An error description string is returned instead if the
|
|
248
|
+
SMS list cannot be retrieved.
|
|
249
|
+
The example of the resulting data:
|
|
250
|
+
```json
|
|
251
|
+
{
|
|
252
|
+
"items":[
|
|
253
|
+
{
|
|
254
|
+
"id":"2",
|
|
255
|
+
"address":"+123456789",
|
|
256
|
+
"person":null,
|
|
257
|
+
"date":"1581936422203",
|
|
258
|
+
"read":"0",
|
|
259
|
+
"status":"-1",
|
|
260
|
+
"type":"1",
|
|
261
|
+
"subject":null,
|
|
262
|
+
"body":"\"text message2\"",
|
|
263
|
+
"serviceCenter":null
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
"id":"1",
|
|
267
|
+
"address":"+123456789",
|
|
268
|
+
"person":null,
|
|
269
|
+
"date":"1581936382740",
|
|
270
|
+
"read":"0",
|
|
271
|
+
"status":"-1",
|
|
272
|
+
"type":"1",
|
|
273
|
+
"subject":null,
|
|
274
|
+
"body":"\"text message\"",
|
|
275
|
+
"serviceCenter":null
|
|
276
|
+
}
|
|
277
|
+
],
|
|
278
|
+
"total":2
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
|
|
237
283
|
## Notes:
|
|
238
284
|
|
|
239
285
|
* You have to specify the receiver class if the app has never been executed before:
|
|
Binary file
|
package/app/build.gradle
CHANGED
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
|
25
25
|
<uses-permission android:name="android.permission.BLUETOOTH" />
|
|
26
26
|
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
|
27
|
+
<uses-permission android:name="android.permission.READ_SMS" />
|
|
27
28
|
|
|
28
29
|
<uses-feature android:name="android.hardware.wifi" />
|
|
29
30
|
|
|
@@ -128,5 +129,8 @@
|
|
|
128
129
|
<receiver android:name=".receivers.UnpairBluetoothDevicesReceiver"
|
|
129
130
|
android:exported="true"
|
|
130
131
|
tools:ignore="ExportedReceiver" />
|
|
132
|
+
<receiver android:name=".receivers.SmsReader"
|
|
133
|
+
android:exported="true"
|
|
134
|
+
tools:ignore="ExportedReceiver" />
|
|
131
135
|
</application>
|
|
132
136
|
</manifest>
|
|
@@ -50,6 +50,7 @@ public class LocationService extends Service {
|
|
|
50
50
|
private static final String LONGITUDE_PARAMETER_KEY = "longitude";
|
|
51
51
|
private static final String LATITUDE_PARAMETER_KEY = "latitude";
|
|
52
52
|
private static final String ALTITUDE_PARAMETER_KEY = "altitude";
|
|
53
|
+
private static final String SPEED_PARAMETER_KEY = "speed";
|
|
53
54
|
|
|
54
55
|
private static final long UPDATE_INTERVAL_MS = 2000L;
|
|
55
56
|
|
|
@@ -85,7 +86,6 @@ public class LocationService extends Service {
|
|
|
85
86
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
86
87
|
finishForegroundSetup();
|
|
87
88
|
}
|
|
88
|
-
Log.i(TAG, "INTENT " + intent.getExtras());
|
|
89
89
|
|
|
90
90
|
handleIntent(intent);
|
|
91
91
|
|
|
@@ -104,7 +104,9 @@ public class LocationService extends Service {
|
|
|
104
104
|
if (intent == null) {
|
|
105
105
|
return;
|
|
106
106
|
}
|
|
107
|
-
|
|
107
|
+
Log.i(TAG, "INTENT " + intent.getExtras());
|
|
108
|
+
|
|
109
|
+
// update the locationFactory also if the service is already running to mock.
|
|
108
110
|
updateMockLocationFactory(intent);
|
|
109
111
|
scheduleLocationUpdate();
|
|
110
112
|
}
|
|
@@ -196,6 +198,17 @@ public class LocationService extends Service {
|
|
|
196
198
|
Log.e(TAG, String.format("altitude should be a valid number. '%s' is given instead",
|
|
197
199
|
intent.getStringExtra(ALTITUDE_PARAMETER_KEY)));
|
|
198
200
|
}
|
|
201
|
+
try {
|
|
202
|
+
if (intent.hasExtra(SPEED_PARAMETER_KEY)) {
|
|
203
|
+
float speed = Float.valueOf(intent.getStringExtra(SPEED_PARAMETER_KEY));
|
|
204
|
+
|
|
205
|
+
locationFactory.setLocation(latitude, longitude, altitude, speed);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
} catch (NumberFormatException e) {
|
|
209
|
+
Log.e(TAG, String.format("speed should be a valid number larger then 0.0. '%s' is given instead",
|
|
210
|
+
intent.getStringExtra(SPEED_PARAMETER_KEY)));
|
|
211
|
+
}
|
|
199
212
|
|
|
200
213
|
locationFactory.setLocation(latitude, longitude, altitude);
|
|
201
214
|
}
|
|
@@ -35,6 +35,7 @@ import io.appium.settings.receivers.HasAction;
|
|
|
35
35
|
import io.appium.settings.receivers.LocaleSettingReceiver;
|
|
36
36
|
import io.appium.settings.receivers.LocationInfoReceiver;
|
|
37
37
|
import io.appium.settings.receivers.NotificationsReceiver;
|
|
38
|
+
import io.appium.settings.receivers.SmsReader;
|
|
38
39
|
import io.appium.settings.receivers.UnpairBluetoothDevicesReceiver;
|
|
39
40
|
import io.appium.settings.receivers.WiFiConnectionSettingReceiver;
|
|
40
41
|
|
|
@@ -59,6 +60,7 @@ public class Settings extends Activity {
|
|
|
59
60
|
receiverClasses.add(BluetoothConnectionSettingReceiver.class);
|
|
60
61
|
receiverClasses.add(UnpairBluetoothDevicesReceiver.class);
|
|
61
62
|
receiverClasses.add(NotificationsReceiver.class);
|
|
63
|
+
receiverClasses.add(SmsReader.class);
|
|
62
64
|
registerSettingsReceivers(receiverClasses);
|
|
63
65
|
|
|
64
66
|
// https://developer.android.com/about/versions/oreo/background-location-limits
|
|
@@ -67,6 +67,7 @@ public class LocaleSettingHandler extends AbstractSettingHandler {
|
|
|
67
67
|
f.setBoolean(config, true);
|
|
68
68
|
|
|
69
69
|
config.locale = locale;
|
|
70
|
+
config.setLayoutDirection(locale);
|
|
70
71
|
|
|
71
72
|
Method methodUpdateConfiguration = activityManagerNativeClass.getMethod("updateConfiguration", Configuration.class);
|
|
72
73
|
methodUpdateConfiguration.setAccessible(true);
|
|
@@ -25,6 +25,8 @@ public class LocationFactory {
|
|
|
25
25
|
private double latitude;
|
|
26
26
|
private double longitude;
|
|
27
27
|
private double altitude;
|
|
28
|
+
private float speed;
|
|
29
|
+
private boolean hasSpeed = false;
|
|
28
30
|
|
|
29
31
|
|
|
30
32
|
public synchronized Location createLocation(String providerName, float accuracy) {
|
|
@@ -34,7 +36,9 @@ public class LocationFactory {
|
|
|
34
36
|
l.setLatitude(latitude);
|
|
35
37
|
l.setLongitude(longitude);
|
|
36
38
|
l.setAltitude(altitude);
|
|
37
|
-
|
|
39
|
+
if (hasSpeed) {
|
|
40
|
+
l.setSpeed(speed);
|
|
41
|
+
}
|
|
38
42
|
l.setBearing(0);
|
|
39
43
|
|
|
40
44
|
l.setTime(System.currentTimeMillis());
|
|
@@ -44,9 +48,16 @@ public class LocationFactory {
|
|
|
44
48
|
return l;
|
|
45
49
|
}
|
|
46
50
|
|
|
51
|
+
public synchronized void setLocation(double latitude, double longitude, double altitude, float speed) {
|
|
52
|
+
this.setLocation(latitude, longitude, altitude);
|
|
53
|
+
this.speed = speed;
|
|
54
|
+
this.hasSpeed = true;
|
|
55
|
+
}
|
|
56
|
+
|
|
47
57
|
public synchronized void setLocation(double latitude, double longitude, double altitude) {
|
|
48
58
|
this.latitude = latitude;
|
|
49
59
|
this.longitude = longitude;
|
|
50
60
|
this.altitude = altitude;
|
|
61
|
+
this.hasSpeed = false;
|
|
51
62
|
}
|
|
52
63
|
}
|
|
@@ -45,7 +45,7 @@ public class LocationInfoReceiver extends BroadcastReceiver
|
|
|
45
45
|
if (location != null) {
|
|
46
46
|
setResultCode(Activity.RESULT_OK);
|
|
47
47
|
// Decimal separator is a dot
|
|
48
|
-
setResultData(String.format(Locale.US, "%.
|
|
48
|
+
setResultData(String.format(Locale.US, "%.7f %.7f %.7f",
|
|
49
49
|
location.getLatitude(), location.getLongitude(), location.getAltitude()));
|
|
50
50
|
} else {
|
|
51
51
|
setResultCode(Activity.RESULT_CANCELED);
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2012-present Appium Committers
|
|
3
|
+
<p>
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
<p>
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
<p>
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
package io.appium.settings.receivers;
|
|
18
|
+
|
|
19
|
+
import android.app.Activity;
|
|
20
|
+
import android.content.BroadcastReceiver;
|
|
21
|
+
import android.content.Context;
|
|
22
|
+
import android.content.Intent;
|
|
23
|
+
import android.database.Cursor;
|
|
24
|
+
import android.net.Uri;
|
|
25
|
+
import android.util.Log;
|
|
26
|
+
import org.json.JSONArray;
|
|
27
|
+
import org.json.JSONException;
|
|
28
|
+
import org.json.JSONObject;
|
|
29
|
+
|
|
30
|
+
import static io.appium.settings.helpers.Utils.formatJsonNull;
|
|
31
|
+
|
|
32
|
+
public class SmsReader extends BroadcastReceiver implements HasAction {
|
|
33
|
+
private static final String TAG = SmsReader.class.getSimpleName();
|
|
34
|
+
private static final Uri INCOMING_SMS = Uri.parse("content://sms/inbox");
|
|
35
|
+
private static final String ACTION = "io.appium.settings.sms.read";
|
|
36
|
+
private static final int MAX_ITEMS = 100;
|
|
37
|
+
private static final String MAX_ITEMS_SETTING_NAME = "max";
|
|
38
|
+
private static final String[][] SMS_INFO_MAPPING = new String[][]{
|
|
39
|
+
{"_id", "id"},
|
|
40
|
+
{"address", "address"},
|
|
41
|
+
{"person", "person"},
|
|
42
|
+
{"date", "date"},
|
|
43
|
+
{"read", "read"},
|
|
44
|
+
{"status", "status"},
|
|
45
|
+
{"type", "type"},
|
|
46
|
+
{"subject", "subject"},
|
|
47
|
+
{"body", "body"},
|
|
48
|
+
{"service_center", "serviceCenter"}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
private JSONObject listSms(Context context, int maxCount) throws JSONException {
|
|
52
|
+
Cursor cursor = context.getContentResolver().query(INCOMING_SMS,
|
|
53
|
+
null, null, null, "date desc");
|
|
54
|
+
//noinspection TryFinallyCanBeTryWithResources
|
|
55
|
+
try {
|
|
56
|
+
JSONArray items = new JSONArray();
|
|
57
|
+
if (cursor != null && cursor.moveToFirst()) {
|
|
58
|
+
do {
|
|
59
|
+
JSONObject item = new JSONObject();
|
|
60
|
+
for (String[] entry : SMS_INFO_MAPPING) {
|
|
61
|
+
int columnIndex = cursor.getColumnIndex(entry[0]);
|
|
62
|
+
if (columnIndex >= 0) {
|
|
63
|
+
item.put(entry[1], formatJsonNull(cursor.getString(columnIndex)));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
items.put(item);
|
|
67
|
+
} while (cursor.moveToNext() && items.length() < maxCount);
|
|
68
|
+
}
|
|
69
|
+
JSONObject result = new JSONObject();
|
|
70
|
+
result.put("items", items);
|
|
71
|
+
result.put("total", cursor == null ? 0 : cursor.getCount());
|
|
72
|
+
return result;
|
|
73
|
+
} finally {
|
|
74
|
+
if (cursor != null) {
|
|
75
|
+
cursor.close();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Responds to broadcast requests like
|
|
82
|
+
* am broadcast -a io.appium.settings.sms.read --es max 10
|
|
83
|
+
* with the list of the recent SMS messages formatted as JSON
|
|
84
|
+
*/
|
|
85
|
+
@Override
|
|
86
|
+
public void onReceive(Context context, Intent intent) {
|
|
87
|
+
int maxItems = MAX_ITEMS;
|
|
88
|
+
if (intent.hasExtra(MAX_ITEMS_SETTING_NAME)) {
|
|
89
|
+
try {
|
|
90
|
+
maxItems = Integer.parseInt(intent.getStringExtra(MAX_ITEMS_SETTING_NAME));
|
|
91
|
+
} catch (NumberFormatException e) {
|
|
92
|
+
e.printStackTrace();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
Log.d(TAG, String.format("Getting the recent %s SMS messages", maxItems));
|
|
96
|
+
String output;
|
|
97
|
+
try {
|
|
98
|
+
output = listSms(context, maxItems).toString();
|
|
99
|
+
} catch (Exception e) {
|
|
100
|
+
e.printStackTrace();
|
|
101
|
+
output = "Appium Settings helper is unable to list SMS messages. " +
|
|
102
|
+
"Check the logcat output for more details.";
|
|
103
|
+
Log.e(TAG, output);
|
|
104
|
+
}
|
|
105
|
+
setResultCode(Activity.RESULT_OK);
|
|
106
|
+
setResultData(output);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
@Override
|
|
110
|
+
public String getAction() {
|
|
111
|
+
return ACTION;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -69,9 +69,10 @@ public class UnpairBluetoothDevicesReceiver extends BroadcastReceiver implements
|
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
private void unpairBluetoothDevice(BluetoothDevice device)
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
private void unpairBluetoothDevice(BluetoothDevice device)
|
|
73
|
+
throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
|
|
74
|
+
//noinspection JavaReflectionMemberAccess
|
|
75
|
+
device.getClass().getMethod("removeBond").invoke(device);
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
@Override
|
package/build.gradle
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
#Tue May 19 12:07:24 CEST 2020
|
|
2
2
|
distributionBase=GRADLE_USER_HOME
|
|
3
|
-
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
|
|
4
3
|
distributionPath=wrapper/dists
|
|
5
|
-
zipStorePath=wrapper/dists
|
|
6
4
|
zipStoreBase=GRADLE_USER_HOME
|
|
5
|
+
zipStorePath=wrapper/dists
|
|
6
|
+
distributionUrl=https\://services.gradle.org/distributions/gradle-6.4.1-all.zip
|