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 CHANGED
@@ -1,7 +1,5 @@
1
1
  # Settings
2
2
 
3
- [![Greenkeeper badge](https://badges.greenkeeper.io/appium/io.appium.settings.svg)](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
@@ -7,8 +7,8 @@ android {
7
7
  defaultConfig {
8
8
  minSdkVersion 18
9
9
  targetSdkVersion 28
10
- versionCode 25
11
- versionName "3.0.1"
10
+ versionCode 29
11
+ versionName "3.3.0"
12
12
  applicationId "io.appium.settings"
13
13
  }
14
14
 
@@ -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
- // update the locationFactory also if the service is already running to mock
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
- l.setSpeed(0);
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, "%.5f %.5f %.5f",
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) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
73
- //noinspection JavaReflectionMemberAccess,ConstantConditions,ConfusingArgumentToVarargsMethod
74
- device.getClass().getMethod("removeBond", null).invoke(device, null);
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
@@ -5,7 +5,7 @@ buildscript {
5
5
  jcenter()
6
6
  }
7
7
  dependencies {
8
- classpath 'com.android.tools.build:gradle:3.5.3'
8
+ classpath 'com.android.tools.build:gradle:4.0.2'
9
9
  }
10
10
  }
11
11
 
@@ -1,6 +1,6 @@
1
- #Thu Dec 19 12:41:17 CET 2019
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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "io.appium.settings",
3
- "version": "3.0.1",
3
+ "version": "3.3.0",
4
4
  "description": "App for dealing with Android settings",
5
5
  "main": "index.js",
6
6
  "scripts": {