1
0
mirror of https://github.com/nerzhul/ownCloud-SMS-App.git synced 2026-08-20 21:03:08 +00:00

Replace C++ with Cmake with GoLang gomobile

* Add ncsmsgo.arr which is the GoLang gomobile part
See: https://gitlab.com/nerzhul/ncsmsgo
* Android-NDK is not needed anymore
* Android app getVersion() now uses the Golang part
* Use the next getLastHTTPStatus() call in getVersion()
* Android app pushSms() now uses the Golang part
* JNI SmsBuffer has been replaced with GoLang aar bindings
-> This permits to remove some java code & increase performance
* Prepare a insecure switch flag to the Golang client
This commit is contained in:
Loic Blot
2018-02-08 23:19:25 +01:00
committed by Loïc Blot
parent 5317dc4fd9
commit d57810b5d8
30 changed files with 138 additions and 725 deletions
@@ -208,7 +208,7 @@ public class AppCompatListActivity extends AppCompatActivity {
super.onContentChanged();
View emptyView = findViewById(R.id.empty);
mList = (ListView)findViewById(R.id.list);
mList = findViewById(R.id.list);
if (mList == null) {
throw new RuntimeException(
"Your content must have a ListView whose id attribute is " +
@@ -44,8 +44,6 @@ import android.widget.TextView;
import com.dd.processbutton.iml.ActionProcessButton;
import org.json.JSONObject;
import java.net.MalformedURLException;
import java.net.URL;
@@ -85,11 +83,11 @@ public class LoginActivity extends AppCompatActivity {
actionBar.setDisplayHomeAsUpEnabled(true);
// Set up the login form.
_protocolView = (Spinner) findViewById(R.id.oc_protocol);
_serverView = (EditText) findViewById(R.id.oc_server);
_loginView = (EditText) findViewById(R.id.oc_login);
_protocolView = findViewById(R.id.oc_protocol);
_serverView = findViewById(R.id.oc_server);
_loginView = findViewById(R.id.oc_login);
_passwordView = (EditText) findViewById(R.id.oc_password);
_passwordView = findViewById(R.id.oc_password);
_passwordView
.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
@@ -103,7 +101,7 @@ public class LoginActivity extends AppCompatActivity {
}
});
_signInButton = (ActionProcessButton) findViewById(R.id.oc_signin_button);
_signInButton = findViewById(R.id.oc_signin_button);
_signInButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
@@ -270,8 +268,8 @@ public class LoginActivity extends AppCompatActivity {
_returnCode = 0;
OCHttpClient http = new OCHttpClient(getBaseContext(), _serverURL, _login, _password);
try {
Pair<Integer, JSONObject> response = http.getVersion();
_returnCode = response.first;
Pair<Integer, Integer> vPair = http.getVersion();
_returnCode = vPair.first;
} catch (IllegalArgumentException e) {
Log.w(TAG, "Failed to getVersion, IllegalArgumentException occured: " + e.getMessage());
_returnCode = 597;
@@ -76,7 +76,7 @@ public class MainActivity extends AppCompatActivity
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer = findViewById(R.id.drawer_layout);
setupDrawer();
drawer.openDrawer(GravityCompat.START);
}
@@ -93,7 +93,7 @@ public class MainActivity extends AppCompatActivity
toggle.syncState();
toggle.setDrawerIndicatorEnabled(true);
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
NavigationView navigationView = findViewById(R.id.nav_view);
assert navigationView != null;
navigationView.setNavigationItemSelectedListener(this);
}
@@ -55,12 +55,12 @@ public class ContactListActivity extends AppCompatActivity implements ASyncConta
mObjects = new ArrayList<>();
setContentView(R.layout.restore_activity_contactlist);
mLayout = (SwipeRefreshLayout) findViewById(R.id.contactlist_swipe_container);
mLayout = findViewById(R.id.contactlist_swipe_container);
mAdapter = new ContactListAdapter(getBaseContext(), mObjects);
mContactInfos = (LinearLayout) findViewById(R.id.contactinfos_layout);
ListView contactPhoneListView = (ListView) findViewById(R.id.contact_phonelistView);
mContactInfos = findViewById(R.id.contactinfos_layout);
ListView contactPhoneListView = findViewById(R.id.contact_phonelistView);
mContactPhoneListAdapter = new RecoveryPhoneNumberListViewAdapter(getBaseContext());
assert contactPhoneListView != null;
contactPhoneListView.setAdapter(mContactPhoneListAdapter);
@@ -72,7 +72,7 @@ public class ContactListActivity extends AppCompatActivity implements ASyncConta
}
private void createAccountList() {
final ProgressBar contactProgressBar = (ProgressBar) findViewById(R.id.contactlist_pgbar);
final ProgressBar contactProgressBar = findViewById(R.id.contactlist_pgbar);
assert contactProgressBar != null;
String accountName = getIntent().getExtras().getString("account");
@@ -112,7 +112,7 @@ public class ContactListActivity extends AppCompatActivity implements ASyncConta
}
private void initSpinner() {
final Spinner sp = (Spinner) findViewById(R.id.contact_spinner);
final Spinner sp = findViewById(R.id.contact_spinner);
assert sp != null;
sp.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
@@ -73,9 +73,9 @@ public class RestoreMessagesActivity extends AppCompatActivity {
}
initInterface();
Button fix_button = (Button) findViewById(R.id.button_fix_permissions);
final Button launch_restore = (Button) findViewById(R.id.button_launch_restore);
final ProgressBar pb = (ProgressBar) findViewById(R.id.progressbar_restore);
Button fix_button = findViewById(R.id.button_fix_permissions);
final Button launch_restore = findViewById(R.id.button_launch_restore);
final ProgressBar pb = findViewById(R.id.progressbar_restore);
final RestoreMessagesActivity me = this;
fix_button.setOnClickListener(new View.OnClickListener() {
@@ -130,13 +130,13 @@ public class RestoreMessagesActivity extends AppCompatActivity {
}
private void initInterface() {
TextView tv_error = (TextView) findViewById(R.id.tv_error_default_smsapp);
TextView tv_error = findViewById(R.id.tv_error_default_smsapp);
tv_error.setText(R.string.error_make_default_sms_app);
findViewById(R.id.tv_restore_finished).setVisibility(View.INVISIBLE);
findViewById(R.id.tv_progress_value).setVisibility(View.INVISIBLE);
Button fix_button = (Button) findViewById(R.id.button_fix_permissions);
Button launch_restore = (Button) findViewById(R.id.button_launch_restore);
ProgressBar pb = (ProgressBar) findViewById(R.id.progressbar_restore);
Button fix_button = findViewById(R.id.button_fix_permissions);
Button launch_restore = findViewById(R.id.button_launch_restore);
ProgressBar pb = findViewById(R.id.progressbar_restore);
pb.setVisibility(View.INVISIBLE);
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.KITKAT) {
@@ -158,10 +158,10 @@ public class RestoreMessagesActivity extends AppCompatActivity {
}
private void errorNotification(int err) {
TextView tv = (TextView) findViewById(R.id.tv_error_default_smsapp);
Button fix_button = (Button) findViewById(R.id.button_fix_permissions);
Button launch_restore = (Button) findViewById(R.id.button_launch_restore);
ProgressBar pb = (ProgressBar) findViewById(R.id.progressbar_restore);
TextView tv = findViewById(R.id.tv_error_default_smsapp);
Button fix_button = findViewById(R.id.button_fix_permissions);
Button launch_restore = findViewById(R.id.button_launch_restore);
ProgressBar pb = findViewById(R.id.progressbar_restore);
tv.setText(err);
tv.setVisibility(View.VISIBLE);
fix_button.setVisibility(View.INVISIBLE);
@@ -182,9 +182,9 @@ public class RestoreMessagesActivity extends AppCompatActivity {
switch (requestCode) {
case RestoreMessagesActivity.REQUEST_DEFAULT_SMSAPP:
if (resultCode == Activity.RESULT_OK) {
TextView tv = (TextView) findViewById(R.id.tv_error_default_smsapp);
Button fix_button = (Button) findViewById(R.id.button_fix_permissions);
Button launch_restore = (Button) findViewById(R.id.button_launch_restore);
TextView tv = findViewById(R.id.tv_error_default_smsapp);
Button fix_button = findViewById(R.id.button_fix_permissions);
Button launch_restore = findViewById(R.id.button_launch_restore);
tv.setVisibility(View.INVISIBLE);
fix_button.setVisibility(View.INVISIBLE);
launch_restore.setVisibility(View.VISIBLE);
@@ -225,7 +225,7 @@ public class RestoreMessagesActivity extends AppCompatActivity {
}
public void onProgressUpdate(Integer value) {
TextView tv_progress = (TextView) findViewById(R.id.tv_progress_value);
TextView tv_progress = findViewById(R.id.tv_progress_value);
if (tv_progress.getVisibility() == View.INVISIBLE) {
tv_progress.setVisibility(View.VISIBLE);
}
@@ -43,7 +43,7 @@ public class AndroidAccountAdapter extends ArrayAdapter<Account> {
final Account account = _accounts.get(position);
if (account != null) {
TextView label = (TextView) v.findViewById(AndroidAccountAdapter._accountFieldId);
TextView label = v.findViewById(AndroidAccountAdapter._accountFieldId);
if (label != null) {
label.setText(account.name + " >");
v.setOnClickListener(new OnClickListener() {
@@ -39,7 +39,7 @@ public class ContactListAdapter extends ArrayAdapter<String> {
String element = _objects.get(position);
if (element != null) {
TextView label = (TextView) v.findViewById(ContactListAdapter._fieldId);
TextView label = v.findViewById(ContactListAdapter._fieldId);
if (label != null) {
label.setText(element);
}
@@ -30,7 +30,7 @@ public class RecoveryPhoneNumberListViewAdapter extends ArrayAdapter<String> {
v = inflater.inflate(RecoveryPhoneNumberListViewAdapter._itemLayout, null);
}
TextView label = (TextView) v.findViewById(RecoveryPhoneNumberListViewAdapter._fieldId);
TextView label = v.findViewById(RecoveryPhoneNumberListViewAdapter._fieldId);
if (label != null) {
final String l = getItem(position).toString();
label.setText(getItem(position).toString());
@@ -32,9 +32,9 @@ import fr.unix_experience.owncloud_sms.engine.ASyncSMSSync;
import fr.unix_experience.owncloud_sms.engine.AndroidSmsFetcher;
import fr.unix_experience.owncloud_sms.engine.ConnectivityMonitor;
import fr.unix_experience.owncloud_sms.enums.PermissionID;
import fr.unix_experience.owncloud_sms.jni.SmsBuffer;
import fr.unix_experience.owncloud_sms.prefs.OCSMSSharedPrefs;
import fr.unix_experience.owncloud_sms.prefs.PermissionChecker;
import ncsmsgo.SmsBuffer;
public class ConnectivityChanged extends BroadcastReceiver implements ASyncSMSSync {
@@ -28,9 +28,9 @@ import android.widget.Toast;
import fr.unix_experience.owncloud_sms.R;
import fr.unix_experience.owncloud_sms.enums.OCSMSNotificationType;
import fr.unix_experience.owncloud_sms.exceptions.OCSyncException;
import fr.unix_experience.owncloud_sms.jni.SmsBuffer;
import fr.unix_experience.owncloud_sms.notifications.OCSMSNotificationUI;
import fr.unix_experience.owncloud_sms.prefs.OCSMSSharedPrefs;
import ncsmsgo.SmsBuffer;
public interface ASyncSMSSync {
class SyncTask extends AsyncTask<Void, Void, Void> {
@@ -25,8 +25,8 @@ import org.json.JSONArray;
import org.json.JSONException;
import fr.unix_experience.owncloud_sms.enums.MailboxID;
import fr.unix_experience.owncloud_sms.jni.SmsBuffer;
import fr.unix_experience.owncloud_sms.providers.SmsDataProvider;
import ncsmsgo.SmsBuffer;
public class AndroidSmsFetcher {
public AndroidSmsFetcher(Context ct) {
@@ -53,7 +53,14 @@ public class AndroidSmsFetcher {
// Mailbox ID is required by server
entry.mailboxId = mbID.ordinal();
smsBuffer.push(mbID, entry);
smsBuffer.push(entry.id,
mbID.ordinal(),
entry.type,
entry.date,
entry.address,
entry.body,
entry.read ? "true" : "false",
entry.seen ? "true" : "false");
}
while (c.moveToNext());
}
@@ -114,7 +121,14 @@ public class AndroidSmsFetcher {
* aren't indexed in the same mean
*/
entry.mailboxId = mboxId - 1;
results.push(mbID, entry);
results.push(entry.id,
mbID.ordinal(),
entry.type,
entry.date,
entry.address,
entry.body,
entry.read ? "true" : "false",
entry.seen ? "true" : "false");
c.close();
@@ -45,16 +45,12 @@ import fr.unix_experience.owncloud_sms.R;
import fr.unix_experience.owncloud_sms.enums.OCSyncErrorType;
import fr.unix_experience.owncloud_sms.exceptions.OCSyncException;
import fr.unix_experience.owncloud_sms.providers.AndroidVersionProvider;
import ncsmsgo.SmsBuffer;
import ncsmsgo.SmsHTTPClient;
import ncsmsgo.SmsPushResponse;
public class OCHttpClient {
static {
System.loadLibrary("nativesms");
}
public static native String getAllSmsIdsCall();
public static native String getLastMsgTimestamp();
public static native String getPushRoute();
public static native String getVersionCall();
private SmsHTTPClient _smsHttpClient;
private static final String TAG = OCHttpClient.class.getCanonicalName();
private static final String PARAM_PROTOCOL_VERSION = "http.protocol.version";
@@ -63,12 +59,6 @@ public class OCHttpClient {
private final String _username;
private final String _password;
// API v2 calls
private static final String OC_V2_GET_PHONELIST = "/index.php/apps/ocsms/api/v2/phones/list?format=json";
private static final String OC_V2_GET_MESSAGES ="/index.php/apps/ocsms/api/v2/messages/[START]/[LIMIT]?format=json";
private static final String OC_V2_GET_MESSAGES_PHONE ="/index.php/apps/ocsms/api/v2/messages/[PHONENUMBER]/[START]/[LIMIT]?format=json";
private static final String OC_V2_GET_MESSAGES_SENDQUEUE = "/index.php/apps/ocsms/api/v2/messages/sendqueue?format=json";
public OCHttpClient(Context context, URL serverURL, String accountName, String accountPassword) {
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[]{
@@ -97,6 +87,11 @@ public class OCHttpClient {
_username = accountName;
_password = accountPassword;
_smsHttpClient = new SmsHTTPClient();
// @TODO: at a point add a flag to permit insecure connections somewhere instead of trusting them
_smsHttpClient.init(_url.toString(), new AndroidVersionProvider(context).getVersionCode(),
_username, _password, false);
_userAgent = "nextcloud-phonesync (" + new AndroidVersionProvider(context).getVersionCode() + ")";
}
@@ -127,23 +122,46 @@ public class OCHttpClient {
}
Pair<Integer, JSONObject> getAllSmsIds() throws OCSyncException {
return get(OCHttpClient.getAllSmsIdsCall(), false);
return get(_smsHttpClient.getAllSmsIdsCall(), false);
}
public Pair<Integer, JSONObject> getVersion() throws OCSyncException {
return get(OCHttpClient.getVersionCall(), true);
// Perform the GoLang doVersionCall and handle return
public Pair<Integer, Integer> getVersion() throws OCSyncException {
Integer serverAPIVersion = (int) _smsHttpClient.doVersionCall();
int httpStatus = (int) _smsHttpClient.getLastHTTPStatus();
// If last status is not 200, send the wrong status now
if (httpStatus != 200) {
return new Pair<>(httpStatus, 0);
}
if (serverAPIVersion > 0) {
return new Pair<>(200, serverAPIVersion);
}
else if (serverAPIVersion == 0) {
// Return default version
return new Pair<>(200, 1);
}
else if (serverAPIVersion == -1) {
// This return code from API means I/O error
throw new OCSyncException(R.string.err_sync_http_request_ioexception, OCSyncErrorType.IO);
}
else {
throw new OCSyncException(R.string.err_sync_http_request_returncode_unhandled, OCSyncErrorType.SERVER_ERROR);
}
}
Pair<Integer, JSONObject> pushSms(String smsBuf) throws OCSyncException {
return post(OCHttpClient.getPushRoute(), smsBuf);
Pair<Integer, SmsPushResponse> pushSms(SmsBuffer smsBuf) throws OCSyncException {
SmsPushResponse spr = _smsHttpClient.doPushCall(smsBuf);
return new Pair<>((int) _smsHttpClient.getLastHTTPStatus(), spr);
}
Pair<Integer, JSONObject> getPhoneList() throws OCSyncException {
return get(OCHttpClient.OC_V2_GET_PHONELIST, true);
return get(_smsHttpClient.getPhoneListCall(), true);
}
Pair<Integer, JSONObject> getMessages(Long start, Integer limit) throws OCSyncException {
return get(OCHttpClient.OC_V2_GET_MESSAGES
return get(_smsHttpClient.getMessagesCall()
.replace("[START]", start.toString())
.replace("[LIMIT]", limit.toString()), false);
}
@@ -33,8 +33,9 @@ import java.net.URL;
import fr.unix_experience.owncloud_sms.R;
import fr.unix_experience.owncloud_sms.enums.OCSyncErrorType;
import fr.unix_experience.owncloud_sms.exceptions.OCSyncException;
import fr.unix_experience.owncloud_sms.jni.SmsBuffer;
import fr.unix_experience.owncloud_sms.prefs.OCSMSSharedPrefs;
import ncsmsgo.SmsBuffer;
import ncsmsgo.SmsPushResponse;
@SuppressWarnings("deprecation")
public class OCSMSOwnCloudClient {
@@ -56,6 +57,7 @@ public class OCSMSOwnCloudClient {
_http = new OCHttpClient(context,
serverURL, accountManager.getUserData(account, "ocLogin"),
accountManager.getPassword(account));
_connectivityMonitor = new ConnectivityMonitor(_context);
} catch (MalformedURLException e) {
throw new IllegalStateException(context.getString(R.string.err_sync_account_unparsable));
@@ -63,21 +65,13 @@ public class OCSMSOwnCloudClient {
}
public Integer getServerAPIVersion() throws OCSyncException {
Pair<Integer, JSONObject> response = _http.getVersion();
if (response.second == null) {
// Return default version
return 1;
Pair<Integer, Integer> vPair = _http.getVersion();
_serverAPIVersion = vPair.second;
if (vPair.first == 200 && _serverAPIVersion > 0) {
return _serverAPIVersion;
}
try {
_serverAPIVersion = response.second.getInt("version");
}
catch (JSONException e) {
Log.e(OCSMSOwnCloudClient.TAG, "No version received from server, assuming version 1", e);
_serverAPIVersion = 1;
}
return _serverAPIVersion;
return 0;
}
JSONArray getServerPhoneNumbers() throws OCSyncException {
@@ -111,7 +105,7 @@ public class OCSMSOwnCloudClient {
return;
}
// Create new JSONArray to get results
// Create new SmsBuffer to get results
smsBuffer = new SmsBuffer();
}
@@ -120,28 +114,18 @@ public class OCSMSOwnCloudClient {
return;
}
Pair<Integer, JSONObject> response = _http.pushSms(smsBuffer.asRawJsonString());
Pair<Integer, SmsPushResponse> response = _http.pushSms(smsBuffer);
if (response.second == null) {
Log.e(OCSMSOwnCloudClient.TAG,"Request failed. It doesn't return a valid JSON Object");
Log.e(OCSMSOwnCloudClient.TAG,"Push request failed. GoLang response is empty.");
throw new OCSyncException(R.string.err_sync_push_request, OCSyncErrorType.IO);
}
Boolean pushStatus;
String pushMessage;
try {
pushStatus = response.second.getBoolean("status");
pushMessage = response.second.getString("msg");
}
catch (JSONException e) {
Log.e(OCSMSOwnCloudClient.TAG, "Invalid datas received from server", e);
throw new OCSyncException(R.string.err_sync_push_request_resp, OCSyncErrorType.PARSE);
}
// Push was OK, we can save the lastMessageDate which was saved to server
(new OCSMSSharedPrefs(_context)).setLastMessageDate(smsBuffer.getLastMessageDate());
Log.i(OCSMSOwnCloudClient.TAG, "SMS Push request said: status " + pushStatus + " - " + pushMessage);
Log.i(OCSMSOwnCloudClient.TAG, "SMS Push request said: status " +
response.second.getStatus() + " - " + response.second.getMessage());
Log.i(OCSMSOwnCloudClient.TAG, "LastMessageDate set to: " + smsBuffer.getLastMessageDate());
}
@@ -1,69 +0,0 @@
package fr.unix_experience.owncloud_sms.jni;
import fr.unix_experience.owncloud_sms.engine.SmsEntry;
import fr.unix_experience.owncloud_sms.enums.MailboxID;
/**
* Copyright (c) 2014-2017, Loic Blot <loic.blot@unix-experience.fr>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
public class SmsBuffer {
static {
System.loadLibrary("nativesms");
}
private long mHandle;
String TAG = SmsBuffer.class.getSimpleName();
public SmsBuffer() {
mHandle = SmsBuffer.createNativeObject();
}
protected void finalize() throws Throwable {
clear();
super.finalize();
}
private static native long createNativeObject();
private native void deleteNativeObject();
public native void push(int id, int mbid, int type, long date, String address,
String body, String read, String seen);
public native boolean empty();
public native void print();
public native String asRawJsonString();
public native long getLastMessageDate();
public void push(MailboxID mbid, SmsEntry smsEntry) {
push(smsEntry.id,
mbid.ordinal(),
smsEntry.type,
smsEntry.date,
smsEntry.address,
smsEntry.body,
smsEntry.read ? "true" : "false",
smsEntry.seen ? "true" : "false");
}
public void clear() {
if (mHandle == 0) {
return;
}
deleteNativeObject();
mHandle = 0;
}
}
@@ -32,8 +32,8 @@ import fr.unix_experience.owncloud_sms.engine.ConnectivityMonitor;
import fr.unix_experience.owncloud_sms.engine.OCSMSOwnCloudClient;
import fr.unix_experience.owncloud_sms.enums.MailboxID;
import fr.unix_experience.owncloud_sms.enums.PermissionID;
import fr.unix_experience.owncloud_sms.jni.SmsBuffer;
import fr.unix_experience.owncloud_sms.prefs.PermissionChecker;
import ncsmsgo.SmsBuffer;
public class SmsObserver extends ContentObserver implements ASyncSMSSync {