mirror of
https://github.com/aljazceru/Android-nRF-Toolbox.git
synced 2025-12-21 16:34:23 +01:00
Version 1.17.0
This commit is contained in:
@@ -2,14 +2,14 @@ apply plugin: 'com.android.application'
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 24
|
compileSdkVersion 24
|
||||||
buildToolsVersion '23.0.3'
|
buildToolsVersion '24.0.2'
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "no.nordicsemi.android.nrftoolbox"
|
applicationId "no.nordicsemi.android.nrftoolbox"
|
||||||
minSdkVersion 18
|
minSdkVersion 18
|
||||||
targetSdkVersion 24
|
targetSdkVersion 24
|
||||||
versionCode 44
|
versionCode 46
|
||||||
versionName "1.16.5"
|
versionName "1.17.0"
|
||||||
}
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
@@ -22,8 +22,8 @@ android {
|
|||||||
dependencies {
|
dependencies {
|
||||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
compile 'com.google.android.gms:play-services-wearable:9.2.0'
|
compile 'com.google.android.gms:play-services-wearable:9.2.0'
|
||||||
compile 'com.android.support:appcompat-v7:24.0.0'
|
compile 'com.android.support:appcompat-v7:24.2.0'
|
||||||
compile 'com.android.support:design:24.0.0'
|
compile 'com.android.support:design:24.2.0'
|
||||||
compile 'no.nordicsemi.android.support.v18:scanner:0.2.0'
|
compile 'no.nordicsemi.android.support.v18:scanner:0.2.0'
|
||||||
compile 'no.nordicsemi.android:log:2.0.0'
|
compile 'no.nordicsemi.android:log:2.0.0'
|
||||||
compile('org.simpleframework:simple-xml:2.7.1') {
|
compile('org.simpleframework:simple-xml:2.7.1') {
|
||||||
@@ -35,7 +35,7 @@ dependencies {
|
|||||||
wearApp project(':wear')
|
wearApp project(':wear')
|
||||||
|
|
||||||
// The DFU Library is imported automatically from jcenter.
|
// The DFU Library is imported automatically from jcenter.
|
||||||
compile 'no.nordicsemi.android:dfu:0.6.3'
|
compile 'no.nordicsemi.android:dfu:1.0.0'
|
||||||
// If you want to make some changes in the DFU Library, clone the https://github.com/NordicSemiconductor/Android-DFU-Library project into DFULibrary folder,
|
// If you want to make some changes in the DFU Library, clone the https://github.com/NordicSemiconductor/Android-DFU-Library project into DFULibrary folder,
|
||||||
// add it as a module in Project Structure and uncomment the following line:
|
// add it as a module in Project Structure and uncomment the following line:
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||||
|
<uses-permission android:name="android.permission.NFC" />
|
||||||
<uses-permission android:name="no.nordicsemi.android.LOG" />
|
<uses-permission android:name="no.nordicsemi.android.LOG" />
|
||||||
|
|
||||||
<uses-feature
|
<uses-feature
|
||||||
@@ -54,6 +55,14 @@
|
|||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
|
||||||
|
<data android:mimeType="application/vnd.no.nordicsemi.type.app"/>
|
||||||
|
<data android:mimeType="application/vnd.no.nordicsemi.type.address"/>
|
||||||
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name="no.nordicsemi.android.nrftoolbox.FeaturesActivity"
|
android:name="no.nordicsemi.android.nrftoolbox.FeaturesActivity"
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ import android.widget.Toast;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import no.nordicsemi.android.nrftoolbox.adapter.AppAdapter;
|
import no.nordicsemi.android.nrftoolbox.adapter.AppAdapter;
|
||||||
|
import no.nordicsemi.android.nrftoolbox.hrs.HRSActivity;
|
||||||
|
|
||||||
public class FeaturesActivity extends AppCompatActivity {
|
public class FeaturesActivity extends AppCompatActivity {
|
||||||
private static final String NRF_CONNECT_CATEGORY = "no.nordicsemi.android.nrftoolbox.LAUNCHER";
|
private static final String NRF_CONNECT_CATEGORY = "no.nordicsemi.android.nrftoolbox.LAUNCHER";
|
||||||
@@ -58,6 +59,10 @@ public class FeaturesActivity extends AppCompatActivity {
|
|||||||
private static final String NRF_CONNECT_CLASS = NRF_CONNECT_PACKAGE + ".DeviceListActivity";
|
private static final String NRF_CONNECT_CLASS = NRF_CONNECT_PACKAGE + ".DeviceListActivity";
|
||||||
private static final String NRF_CONNECT_MARKET_URI = "market://details?id=no.nordicsemi.android.mcp";
|
private static final String NRF_CONNECT_MARKET_URI = "market://details?id=no.nordicsemi.android.mcp";
|
||||||
|
|
||||||
|
// Extras that can be passed from NFC (see SplashscreenActivity)
|
||||||
|
public static final String EXTRA_APP = "application/vnd.no.nordicsemi.type.app";
|
||||||
|
public static final String EXTRA_ADDRESS = "application/vnd.no.nordicsemi.type.address";
|
||||||
|
|
||||||
private DrawerLayout mDrawerLayout;
|
private DrawerLayout mDrawerLayout;
|
||||||
private ActionBarDrawerToggle mDrawerToggle;
|
private ActionBarDrawerToggle mDrawerToggle;
|
||||||
|
|
||||||
@@ -84,7 +89,7 @@ public class FeaturesActivity extends AppCompatActivity {
|
|||||||
super.onDrawerSlide(drawerView, 0);
|
super.onDrawerSlide(drawerView, 0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
drawer.setDrawerListener(mDrawerToggle);
|
drawer.addDrawerListener(mDrawerToggle);
|
||||||
|
|
||||||
// setup plug-ins in the drawer
|
// setup plug-ins in the drawer
|
||||||
setupPluginsInDrawer((ViewGroup) drawer.findViewById(R.id.plugin_container));
|
setupPluginsInDrawer((ViewGroup) drawer.findViewById(R.id.plugin_container));
|
||||||
@@ -95,6 +100,22 @@ public class FeaturesActivity extends AppCompatActivity {
|
|||||||
grid.setEmptyView(findViewById(android.R.id.empty));
|
grid.setEmptyView(findViewById(android.R.id.empty));
|
||||||
|
|
||||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||||
|
|
||||||
|
final Intent intent = getIntent();
|
||||||
|
if (intent.hasExtra(EXTRA_APP) && intent.hasExtra(EXTRA_ADDRESS)) {
|
||||||
|
final String app = intent.getStringExtra(EXTRA_APP);
|
||||||
|
switch (app) {
|
||||||
|
case "HRM":
|
||||||
|
final Intent newIntent = new Intent(this, HRSActivity.class);
|
||||||
|
newIntent.putExtra(EXTRA_ADDRESS, intent.getByteArrayExtra(EXTRA_ADDRESS));
|
||||||
|
newIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
|
||||||
|
startActivity(newIntent);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// other are not supported yet
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -23,8 +23,12 @@ package no.nordicsemi.android.nrftoolbox;
|
|||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.nfc.NdefMessage;
|
||||||
|
import android.nfc.NdefRecord;
|
||||||
|
import android.nfc.NfcAdapter;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
public class SplashscreenActivity extends Activity {
|
public class SplashscreenActivity extends Activity {
|
||||||
/** Splash screen duration time in milliseconds */
|
/** Splash screen duration time in milliseconds */
|
||||||
@@ -39,9 +43,34 @@ public class SplashscreenActivity extends Activity {
|
|||||||
new Handler().postDelayed(new Runnable() {
|
new Handler().postDelayed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
final Intent intent = new Intent(SplashscreenActivity.this, FeaturesActivity.class);
|
final Intent newIntent = new Intent(SplashscreenActivity.this, FeaturesActivity.class);
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
|
newIntent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
|
||||||
startActivity(intent);
|
|
||||||
|
// Handle NFC message, if app was opened using NFC AAR record
|
||||||
|
final Intent intent = getIntent();
|
||||||
|
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
|
||||||
|
final Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
|
||||||
|
if (rawMsgs != null) {
|
||||||
|
for (int i = 0; i < rawMsgs.length; i++) {
|
||||||
|
final NdefMessage msg = (NdefMessage) rawMsgs[i];
|
||||||
|
final NdefRecord[] records = msg.getRecords();
|
||||||
|
|
||||||
|
for (NdefRecord record : records) {
|
||||||
|
if (record.getTnf() == NdefRecord.TNF_MIME_MEDIA) {
|
||||||
|
switch (record.toMimeType()) {
|
||||||
|
case FeaturesActivity.EXTRA_APP:
|
||||||
|
newIntent.putExtra(FeaturesActivity.EXTRA_APP, new String(record.getPayload()));
|
||||||
|
break;
|
||||||
|
case FeaturesActivity.EXTRA_ADDRESS:
|
||||||
|
newIntent.putExtra(FeaturesActivity.EXTRA_ADDRESS, invertEndianness(record.getPayload()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
startActivity(newIntent);
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
}, DELAY);
|
}, DELAY);
|
||||||
@@ -52,4 +81,18 @@ public class SplashscreenActivity extends Activity {
|
|||||||
// do nothing. Protect from exiting the application when splash screen is shown
|
// do nothing. Protect from exiting the application when splash screen is shown
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inverts endianness of the byte array.
|
||||||
|
* @param bytes input byte array
|
||||||
|
* @return byte array in opposite order
|
||||||
|
*/
|
||||||
|
private byte[] invertEndianness(final byte[] bytes) {
|
||||||
|
if (bytes == null)
|
||||||
|
return null;
|
||||||
|
final int length = bytes.length;
|
||||||
|
final byte[] result = new byte[length];
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
|
result[i] = bytes[length - i - 1];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,9 @@
|
|||||||
*/
|
*/
|
||||||
package no.nordicsemi.android.nrftoolbox.hrs;
|
package no.nordicsemi.android.nrftoolbox.hrs;
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothAdapter;
|
||||||
|
import android.bluetooth.BluetoothDevice;
|
||||||
|
import android.content.Intent;
|
||||||
import android.graphics.Point;
|
import android.graphics.Point;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
@@ -32,6 +35,7 @@ import org.achartengine.GraphicalView;
|
|||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import no.nordicsemi.android.nrftoolbox.FeaturesActivity;
|
||||||
import no.nordicsemi.android.nrftoolbox.R;
|
import no.nordicsemi.android.nrftoolbox.R;
|
||||||
import no.nordicsemi.android.nrftoolbox.profile.BleManager;
|
import no.nordicsemi.android.nrftoolbox.profile.BleManager;
|
||||||
import no.nordicsemi.android.nrftoolbox.profile.BleProfileActivity;
|
import no.nordicsemi.android.nrftoolbox.profile.BleProfileActivity;
|
||||||
@@ -83,18 +87,31 @@ public class HRSActivity extends BleProfileActivity implements HRSManagerCallbac
|
|||||||
layout.addView(mGraphView);
|
layout.addView(mGraphView);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
|
||||||
|
final Intent intent = getIntent();
|
||||||
|
if (!isDeviceConnected() && intent.hasExtra(FeaturesActivity.EXTRA_ADDRESS)) {
|
||||||
|
final BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||||
|
final BluetoothDevice device = bluetoothAdapter.getRemoteDevice(getIntent().getByteArrayExtra(FeaturesActivity.EXTRA_ADDRESS));
|
||||||
|
onDeviceSelected(device, device.getName());
|
||||||
|
|
||||||
|
intent.removeExtra(FeaturesActivity.EXTRA_APP);
|
||||||
|
intent.removeExtra(FeaturesActivity.EXTRA_ADDRESS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onRestoreInstanceState(@NonNull final Bundle savedInstanceState) {
|
protected void onRestoreInstanceState(@NonNull final Bundle savedInstanceState) {
|
||||||
super.onRestoreInstanceState(savedInstanceState);
|
super.onRestoreInstanceState(savedInstanceState);
|
||||||
|
|
||||||
if (savedInstanceState != null) {
|
isGraphInProgress = savedInstanceState.getBoolean(GRAPH_STATUS);
|
||||||
isGraphInProgress = savedInstanceState.getBoolean(GRAPH_STATUS);
|
mCounter = savedInstanceState.getInt(GRAPH_COUNTER);
|
||||||
mCounter = savedInstanceState.getInt(GRAPH_COUNTER);
|
mHrmValue = savedInstanceState.getInt(HR_VALUE);
|
||||||
mHrmValue = savedInstanceState.getInt(HR_VALUE);
|
|
||||||
|
|
||||||
if (isGraphInProgress)
|
if (isGraphInProgress)
|
||||||
startShowGraph();
|
startShowGraph();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -228,7 +228,8 @@ public abstract class BleProfileActivity extends AppCompatActivity implements Bl
|
|||||||
mDeviceName = name;
|
mDeviceName = name;
|
||||||
mBleManager.setLogger(mLogSession);
|
mBleManager.setLogger(mLogSession);
|
||||||
mDeviceNameView.setText(name != null ? name : getString(R.string.not_available));
|
mDeviceNameView.setText(name != null ? name : getString(R.string.not_available));
|
||||||
mConnectButton.setText(R.string.action_disconnect);
|
mConnectButton.setText(R.string.action_connecting);
|
||||||
|
mConnectButton.setEnabled(false);
|
||||||
mBleManager.connect(device);
|
mBleManager.connect(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,6 +245,7 @@ public abstract class BleProfileActivity extends AppCompatActivity implements Bl
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
mConnectButton.setText(R.string.action_disconnect);
|
mConnectButton.setText(R.string.action_disconnect);
|
||||||
|
mConnectButton.setEnabled(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -225,7 +225,8 @@ public abstract class BleProfileExpandableListActivity extends ExpandableListAct
|
|||||||
mDeviceName = name;
|
mDeviceName = name;
|
||||||
mBleManager.setLogger(mLogSession);
|
mBleManager.setLogger(mLogSession);
|
||||||
mDeviceNameView.setText(name != null ? name : getString(R.string.not_available));
|
mDeviceNameView.setText(name != null ? name : getString(R.string.not_available));
|
||||||
mConnectButton.setText(R.string.action_disconnect);
|
mConnectButton.setText(R.string.action_connecting);
|
||||||
|
mConnectButton.setEnabled(false);
|
||||||
mBleManager.connect(device);
|
mBleManager.connect(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,6 +242,7 @@ public abstract class BleProfileExpandableListActivity extends ExpandableListAct
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
mConnectButton.setText(R.string.action_disconnect);
|
mConnectButton.setText(R.string.action_disconnect);
|
||||||
|
mConnectButton.setEnabled(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -443,7 +443,8 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
|
|||||||
}
|
}
|
||||||
mDeviceName = name;
|
mDeviceName = name;
|
||||||
mDeviceNameView.setText(name != null ? name : getString(R.string.not_available));
|
mDeviceNameView.setText(name != null ? name : getString(R.string.not_available));
|
||||||
mConnectButton.setText(R.string.action_disconnect);
|
mConnectButton.setText(R.string.action_connecting);
|
||||||
|
mConnectButton.setEnabled(false);
|
||||||
|
|
||||||
// The device may not be in the range but the service will try to connect to it if it reach it
|
// The device may not be in the range but the service will try to connect to it if it reach it
|
||||||
Logger.d(mLogSession, "Creating service...");
|
Logger.d(mLogSession, "Creating service...");
|
||||||
@@ -469,6 +470,7 @@ public abstract class BleProfileServiceReadyActivity<E extends BleProfileService
|
|||||||
public void onDeviceConnected() {
|
public void onDeviceConnected() {
|
||||||
mDeviceNameView.setText(mDeviceName);
|
mDeviceNameView.setText(mDeviceName);
|
||||||
mConnectButton.setText(R.string.action_disconnect);
|
mConnectButton.setText(R.string.action_disconnect);
|
||||||
|
mConnectButton.setEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
<string name="action_settings">Settings</string>
|
<string name="action_settings">Settings</string>
|
||||||
<string name="action_connect">CONNECT</string>
|
<string name="action_connect">CONNECT</string>
|
||||||
<string name="action_select">SELECT DEVICE</string>
|
<string name="action_select">SELECT DEVICE</string>
|
||||||
|
<string name="action_connecting">CONNECTING…</string>
|
||||||
<string name="action_disconnect">DISCONNECT</string>
|
<string name="action_disconnect">DISCONNECT</string>
|
||||||
|
|
||||||
<string name="drawer_open">Open</string>
|
<string name="drawer_open">Open</string>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ buildscript {
|
|||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:2.1.2'
|
classpath 'com.android.tools.build:gradle:2.1.3'
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files
|
||||||
|
|||||||
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
|||||||
#Tue Jun 14 13:22:53 CEST 2016
|
#Thu Aug 18 09:39:27 CEST 2016
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ android {
|
|||||||
applicationId "no.nordicsemi.android.nrftoolbox"
|
applicationId "no.nordicsemi.android.nrftoolbox"
|
||||||
minSdkVersion 20
|
minSdkVersion 20
|
||||||
targetSdkVersion 24
|
targetSdkVersion 24
|
||||||
versionCode 44
|
versionCode 45
|
||||||
versionName "1.16.5"
|
versionName "1.17.0"
|
||||||
}
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
@@ -23,7 +23,7 @@ android {
|
|||||||
dependencies {
|
dependencies {
|
||||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
compile 'com.google.android.support:wearable:1.3.0'
|
compile 'com.google.android.support:wearable:1.3.0'
|
||||||
compile 'com.google.android.gms:play-services-wearable:9.0.2'
|
compile 'com.google.android.gms:play-services-wearable:9.2.0'
|
||||||
compile 'no.nordicsemi.android.support.v18:scanner:0.2.0'
|
compile 'no.nordicsemi.android.support.v18:scanner:0.2.0'
|
||||||
compile project(':common')
|
compile project(':common')
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user