mirror of
https://github.com/nerzhul/ownCloud-SMS-App.git
synced 2025-06-07 16:06:18 +00:00
Publish many sources as AGPLv3. Also set Android 5.0 compat
This commit is contained in:
parent
40dd4c72e2
commit
a554462ff8
85
AndroidManifest.xml
Normal file
85
AndroidManifest.xml
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="fr.unix_experience.owncloud_sms"
|
||||||
|
android:versionCode="15"
|
||||||
|
android:versionName="0.15.5" >
|
||||||
|
<!-- From Android 3.0 to 4.4w -->
|
||||||
|
<uses-sdk
|
||||||
|
android:minSdkVersion="11"
|
||||||
|
android:maxSdkVersion="21"
|
||||||
|
android:targetSdkVersion="19" />
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.READ_SMS" />
|
||||||
|
<!-- For SMS Broadcaster -->
|
||||||
|
<uses-permission android:name="android.permission.RECEIVE_SMS" />
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
|
||||||
|
<!-- For syncer -->
|
||||||
|
<uses-permission android:name="android.permission.READ_SYNC_STATS" />
|
||||||
|
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
|
||||||
|
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
|
||||||
|
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||||
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||||
|
|
||||||
|
<!-- For account management -->
|
||||||
|
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
|
||||||
|
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
|
||||||
|
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
|
||||||
|
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
|
||||||
|
|
||||||
|
<application
|
||||||
|
android:allowBackup="true"
|
||||||
|
android:icon="@drawable/ic_launcher"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:theme="@style/AppTheme" >
|
||||||
|
|
||||||
|
<!-- Related to periodic sync -->
|
||||||
|
<service android:name=".observers.SmsObserverService"
|
||||||
|
android:exported="false" />
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".sync_adapters.SmsSyncService"
|
||||||
|
android:exported="true"
|
||||||
|
android:process=":sync" >
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.content.SyncAdapter" />
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
|
<meta-data
|
||||||
|
android:name="android.content.SyncAdapter"
|
||||||
|
android:resource="@xml/sync_adapter" />
|
||||||
|
</service>
|
||||||
|
|
||||||
|
<provider
|
||||||
|
android:name=".providers.SmsDataProvider"
|
||||||
|
android:authorities="fr.unix_experience.owncloud_sms.datasync.provider">
|
||||||
|
</provider>
|
||||||
|
|
||||||
|
<!-- Related to Login -->
|
||||||
|
<service android:name=".authenticators.OwnCloudAuthenticatorService">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.accounts.AccountAuthenticator" />
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
|
<meta-data
|
||||||
|
android:name="android.accounts.AccountAuthenticator"
|
||||||
|
android:resource="@xml/owncloud_account_authenticator" />
|
||||||
|
</service>
|
||||||
|
|
||||||
|
<receiver android:name=".broadcast_receivers.IncomingSms">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".activities.LoginActivity"
|
||||||
|
android:label="@string/title_activity_login" >
|
||||||
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name="fr.unix_experience.owncloud_sms.activities.GeneralSettingsActivity"
|
||||||
|
android:label="@string/title_activity_general_settings" >
|
||||||
|
</activity>
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
@ -0,0 +1,208 @@
|
|||||||
|
package fr.unix_experience.owncloud_sms.activities;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import android.accounts.Account;
|
||||||
|
import android.accounts.AccountManager;
|
||||||
|
import android.annotation.TargetApi;
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.PeriodicSync;
|
||||||
|
import android.content.res.Configuration;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.preference.ListPreference;
|
||||||
|
import android.preference.Preference;
|
||||||
|
import android.preference.PreferenceActivity;
|
||||||
|
import android.preference.PreferenceFragment;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import fr.unix_experience.owncloud_sms.R;
|
||||||
|
|
||||||
|
public class GeneralSettingsActivity extends PreferenceActivity {
|
||||||
|
private static final boolean ALWAYS_SIMPLE_PREFS = false;
|
||||||
|
static AccountManager mAccountMgr;
|
||||||
|
static String mAccountAuthority;
|
||||||
|
static String mAccountType;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostCreate(Bundle savedInstanceState) {
|
||||||
|
super.onPostCreate(savedInstanceState);
|
||||||
|
|
||||||
|
mAccountMgr = AccountManager.get(getBaseContext());
|
||||||
|
mAccountAuthority = getString(R.string.account_authority);
|
||||||
|
mAccountType = getString(R.string.account_type);
|
||||||
|
setupSimplePreferencesScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows the simplified settings UI if the device configuration if the
|
||||||
|
* device configuration dictates that a simplified, single-pane UI should be
|
||||||
|
* shown.
|
||||||
|
*/
|
||||||
|
private void setupSimplePreferencesScreen() {
|
||||||
|
if (!isSimplePreferences(this)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// In the simplified UI, fragments are not used at all and we instead
|
||||||
|
// use the older PreferenceActivity APIs.
|
||||||
|
addPreferencesFromResource(R.xml.pref_data_sync);
|
||||||
|
|
||||||
|
// Bind the summaries of EditText/List/Dialog/Ringtone preferences to
|
||||||
|
// their values. When their values change, their summaries are updated
|
||||||
|
// to reflect the new value, per the Android Design guidelines.
|
||||||
|
bindPreferenceSummaryToValue(findPreference("sync_frequency"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public boolean onIsMultiPane() {
|
||||||
|
return isXLargeTablet(this) && !isSimplePreferences(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method to determine if the device has an extra-large screen. For
|
||||||
|
* example, 10" tablets are extra-large.
|
||||||
|
*/
|
||||||
|
private static boolean isXLargeTablet(Context context) {
|
||||||
|
return (context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether the simplified settings UI should be shown. This is
|
||||||
|
* true if this is forced via {@link #ALWAYS_SIMPLE_PREFS}, or the device
|
||||||
|
* doesn't have newer APIs like {@link PreferenceFragment}, or the device
|
||||||
|
* doesn't have an extra-large screen. In these cases, a single-pane
|
||||||
|
* "simplified" settings UI should be shown.
|
||||||
|
*/
|
||||||
|
private static boolean isSimplePreferences(Context context) {
|
||||||
|
return ALWAYS_SIMPLE_PREFS
|
||||||
|
|| Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB
|
||||||
|
|| !isXLargeTablet(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A preference value change listener that updates the preference's summary
|
||||||
|
* to reflect its new value.
|
||||||
|
*/
|
||||||
|
private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceChange(Preference preference, Object value) {
|
||||||
|
String stringValue = value.toString();
|
||||||
|
|
||||||
|
if (preference instanceof ListPreference) {
|
||||||
|
// For list preferences, look up the correct display value in
|
||||||
|
// the preference's 'entries' list.
|
||||||
|
ListPreference listPreference = (ListPreference) preference;
|
||||||
|
int index = listPreference.findIndexOfValue(stringValue);
|
||||||
|
|
||||||
|
// Set the summary to reflect the new value.
|
||||||
|
preference
|
||||||
|
.setSummary(index >= 0 ? listPreference.getEntries()[index]
|
||||||
|
: null);
|
||||||
|
|
||||||
|
|
||||||
|
String prefKey = preference.getKey();
|
||||||
|
|
||||||
|
// Handle sync frequency change
|
||||||
|
if (prefKey.equals(new String("sync_frequency"))) {
|
||||||
|
long syncFreq = Long.parseLong((String)value);
|
||||||
|
|
||||||
|
// Get ownCloud SMS account list
|
||||||
|
Account[] myAccountList = mAccountMgr.getAccountsByType(mAccountType);
|
||||||
|
for (int i = 0; i < myAccountList.length; i++) {
|
||||||
|
// And get all authorities for this account
|
||||||
|
List<PeriodicSync> syncList = ContentResolver.getPeriodicSyncs(myAccountList[i], mAccountAuthority);
|
||||||
|
|
||||||
|
boolean foundSameSyncCycle = false;
|
||||||
|
for (int j = 0; j < syncList.size(); j++) {
|
||||||
|
PeriodicSync ps = syncList.get(i);
|
||||||
|
|
||||||
|
if (ps.period == syncFreq && ps.extras.getInt("synctype") == 1) {
|
||||||
|
foundSameSyncCycle = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foundSameSyncCycle == false) {
|
||||||
|
Bundle b = new Bundle();
|
||||||
|
b.putInt("synctype", 1);
|
||||||
|
|
||||||
|
ContentResolver.removePeriodicSync(myAccountList[i],
|
||||||
|
mAccountAuthority, b);
|
||||||
|
ContentResolver.addPeriodicSync(myAccountList[i],
|
||||||
|
mAccountAuthority, b, syncFreq * 60);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// For all other preferences, set the summary to the value's
|
||||||
|
// simple string representation.
|
||||||
|
preference.setSummary(stringValue);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binds a preference's summary to its value. More specifically, when the
|
||||||
|
* preference's value is changed, its summary (line of text below the
|
||||||
|
* preference title) is updated to reflect the value. The summary is also
|
||||||
|
* immediately updated upon calling this method. The exact display format is
|
||||||
|
* dependent on the type of preference.
|
||||||
|
*
|
||||||
|
* @see #sBindPreferenceSummaryToValueListener
|
||||||
|
*/
|
||||||
|
private static void bindPreferenceSummaryToValue(Preference preference) {
|
||||||
|
// Set the listener to watch for value changes.
|
||||||
|
preference
|
||||||
|
.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);
|
||||||
|
|
||||||
|
// Trigger the listener immediately with the preference's
|
||||||
|
// current value.
|
||||||
|
sBindPreferenceSummaryToValueListener.onPreferenceChange(
|
||||||
|
preference,
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(
|
||||||
|
preference.getContext()).getString(
|
||||||
|
preference.getKey(),
|
||||||
|
""
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This fragment shows data and sync preferences only. It is used when the
|
||||||
|
* activity is showing a two-pane settings UI.
|
||||||
|
*/
|
||||||
|
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||||
|
public static class DataSyncPreferenceFragment extends PreferenceFragment {
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
addPreferencesFromResource(R.xml.pref_data_sync);
|
||||||
|
|
||||||
|
// Bind the summaries of EditText/List/Dialog/Ringtone preferences
|
||||||
|
// to their values. When their values change, their summaries are
|
||||||
|
// updated to reflect the new value, per the Android Design
|
||||||
|
// guidelines.
|
||||||
|
bindPreferenceSummaryToValue(findPreference("sync_frequency"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,329 @@
|
|||||||
|
package fr.unix_experience.owncloud_sms.activities;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import android.accounts.Account;
|
||||||
|
import android.accounts.AccountManager;
|
||||||
|
import android.animation.Animator;
|
||||||
|
import android.animation.AnimatorListenerAdapter;
|
||||||
|
import android.annotation.TargetApi;
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.view.KeyEvent;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
|
import android.view.inputmethod.EditorInfo;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.Spinner;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.owncloud.android.lib.common.OwnCloudClient;
|
||||||
|
import com.owncloud.android.lib.common.OwnCloudClientFactory;
|
||||||
|
import com.owncloud.android.lib.common.OwnCloudCredentialsFactory;
|
||||||
|
|
||||||
|
import fr.unix_experience.owncloud_sms.R;
|
||||||
|
import fr.unix_experience.owncloud_sms.authenticators.OwnCloudAuthenticator;
|
||||||
|
import fr.unix_experience.owncloud_sms.enums.LoginReturnCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A login screen that offers login via email/password.
|
||||||
|
*/
|
||||||
|
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||||
|
public class LoginActivity extends Activity {
|
||||||
|
/**
|
||||||
|
* Keep track of the login task to ensure we can cancel it if requested.
|
||||||
|
*/
|
||||||
|
private UserLoginTask mAuthTask = null;
|
||||||
|
|
||||||
|
// UI references.
|
||||||
|
private Spinner _protocolView;
|
||||||
|
private EditText _loginView;
|
||||||
|
private EditText _passwordView;
|
||||||
|
private EditText _serverView;
|
||||||
|
private View mProgressView;
|
||||||
|
private View mLoginFormView;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_login);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
_passwordView = (EditText) findViewById(R.id.oc_password);
|
||||||
|
_passwordView
|
||||||
|
.setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onEditorAction(TextView textView, int id,
|
||||||
|
KeyEvent keyEvent) {
|
||||||
|
if (id == R.id.oc_login || id == EditorInfo.IME_NULL) {
|
||||||
|
attemptLogin();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Button _signInButton = (Button) findViewById(R.id.oc_signin_button);
|
||||||
|
_signInButton.setOnClickListener(new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
attemptLogin();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mLoginFormView = findViewById(R.id.login_form);
|
||||||
|
mProgressView = findViewById(R.id.login_progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to sign in or register the account specified by the login form.
|
||||||
|
* If there are form errors (invalid email, missing fields, etc.), the
|
||||||
|
* errors are presented and no actual login attempt is made.
|
||||||
|
*/
|
||||||
|
public void attemptLogin() {
|
||||||
|
if (mAuthTask != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset errors.
|
||||||
|
_loginView.setError(null);
|
||||||
|
_passwordView.setError(null);
|
||||||
|
|
||||||
|
// Store values at the time of the login attempt.
|
||||||
|
String protocol = _protocolView.getSelectedItem().toString();
|
||||||
|
String login = _loginView.getText().toString();
|
||||||
|
String password = _passwordView.getText().toString();
|
||||||
|
String serverAddr = _serverView.getText().toString();
|
||||||
|
|
||||||
|
boolean cancel = false;
|
||||||
|
View focusView = null;
|
||||||
|
|
||||||
|
// Check for a valid server address.
|
||||||
|
if (TextUtils.isEmpty(protocol)) {
|
||||||
|
cancel = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for a valid server address.
|
||||||
|
if (TextUtils.isEmpty(serverAddr)) {
|
||||||
|
_serverView.setError(getString(R.string.error_field_required));
|
||||||
|
focusView = _loginView;
|
||||||
|
cancel = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for a valid login address.
|
||||||
|
if (TextUtils.isEmpty(login)) {
|
||||||
|
_loginView.setError(getString(R.string.error_field_required));
|
||||||
|
focusView = _loginView;
|
||||||
|
cancel = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for a valid password
|
||||||
|
if (TextUtils.isEmpty(password)) {
|
||||||
|
_passwordView.setError(getString(R.string.error_field_required));
|
||||||
|
focusView = _passwordView;
|
||||||
|
cancel = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isPasswordValid(password)) {
|
||||||
|
_passwordView.setError(getString(R.string.error_invalid_password));
|
||||||
|
focusView = _passwordView;
|
||||||
|
cancel = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cancel) {
|
||||||
|
// There was an error; don't attempt login and focus the first
|
||||||
|
// form field with an error.
|
||||||
|
focusView.requestFocus();
|
||||||
|
} else {
|
||||||
|
// Show a progress spinner, and kick off a background task to
|
||||||
|
// perform the user login attempt.
|
||||||
|
showProgress(true);
|
||||||
|
String serverURL = new String(protocol + serverAddr);
|
||||||
|
mAuthTask = new UserLoginTask(serverURL, login, password);
|
||||||
|
mAuthTask.execute((Void) null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isPasswordValid(String password) {
|
||||||
|
// TODO: Replace this with your own logic
|
||||||
|
return password.length() > 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows the progress UI and hides the login form.
|
||||||
|
*/
|
||||||
|
@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
|
||||||
|
public void showProgress(final boolean show) {
|
||||||
|
// On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow
|
||||||
|
// for very easy animations. If available, use these APIs to fade-in
|
||||||
|
// the progress spinner.
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
|
||||||
|
int shortAnimTime = getResources().getInteger(
|
||||||
|
android.R.integer.config_shortAnimTime);
|
||||||
|
|
||||||
|
mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
|
||||||
|
mLoginFormView.animate().setDuration(shortAnimTime)
|
||||||
|
.alpha(show ? 0 : 1)
|
||||||
|
.setListener(new AnimatorListenerAdapter() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator animation) {
|
||||||
|
mLoginFormView.setVisibility(show ? View.GONE
|
||||||
|
: View.VISIBLE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
|
||||||
|
mProgressView.animate().setDuration(shortAnimTime)
|
||||||
|
.alpha(show ? 1 : 0)
|
||||||
|
.setListener(new AnimatorListenerAdapter() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator animation) {
|
||||||
|
mProgressView.setVisibility(show ? View.VISIBLE
|
||||||
|
: View.GONE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// The ViewPropertyAnimator APIs are not available, so simply show
|
||||||
|
// and hide the relevant UI components.
|
||||||
|
mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
|
||||||
|
mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an asynchronous login/registration task used to authenticate
|
||||||
|
* the user.
|
||||||
|
*/
|
||||||
|
public class UserLoginTask extends AsyncTask<Void, Void, Boolean> {
|
||||||
|
|
||||||
|
UserLoginTask(String serverURI, String login, String password) {
|
||||||
|
_serverURI = Uri.parse(serverURI);
|
||||||
|
_login = login;
|
||||||
|
_password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Boolean doInBackground(Void... params) {
|
||||||
|
// Create client object to perform remote operations
|
||||||
|
OwnCloudClient ocClient = OwnCloudClientFactory.createOwnCloudClient(
|
||||||
|
_serverURI, getBaseContext(),
|
||||||
|
// Activity or Service context
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
// Set basic credentials
|
||||||
|
ocClient.setCredentials(
|
||||||
|
OwnCloudCredentialsFactory.newBasicCredentials(_login, _password)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Send an authentication test to ownCloud
|
||||||
|
OwnCloudAuthenticator at = new OwnCloudAuthenticator(getBaseContext());
|
||||||
|
at.setClient(ocClient);
|
||||||
|
|
||||||
|
_returnCode = at.testCredentials();
|
||||||
|
|
||||||
|
return (_returnCode == LoginReturnCode.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(final Boolean success) {
|
||||||
|
mAuthTask = null;
|
||||||
|
showProgress(false);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
String accountType = getIntent().getStringExtra(PARAM_AUTHTOKEN_TYPE);
|
||||||
|
if (accountType == null) {
|
||||||
|
accountType = getString(R.string.account_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate a label
|
||||||
|
String accountLabel = _login + "@" + _serverURI.getHost();
|
||||||
|
|
||||||
|
// We create the account
|
||||||
|
final Account account = new Account(accountLabel, accountType);
|
||||||
|
Bundle accountBundle = new Bundle();
|
||||||
|
accountBundle.putString("ocLogin", _login);
|
||||||
|
accountBundle.putString("ocURI", _serverURI.toString());
|
||||||
|
|
||||||
|
// And we push it to Android
|
||||||
|
AccountManager accMgr = AccountManager.get(getApplicationContext());
|
||||||
|
accMgr.addAccountExplicitly(account, _password, accountBundle);
|
||||||
|
|
||||||
|
// Set sync options
|
||||||
|
ContentResolver.setSyncAutomatically(account, getString(R.string.account_authority), true);
|
||||||
|
|
||||||
|
Bundle b = new Bundle();
|
||||||
|
b.putInt("synctype", 1);
|
||||||
|
|
||||||
|
ContentResolver.addPeriodicSync(account, getString(R.string.account_authority), b, 15 * 60);
|
||||||
|
// Then it's finished
|
||||||
|
finish();
|
||||||
|
} else {
|
||||||
|
switch (_returnCode) {
|
||||||
|
case INVALID_ADDR:
|
||||||
|
_serverView.setError(getString(R.string.error_invalid_server_address));
|
||||||
|
_serverView.requestFocus();
|
||||||
|
break;
|
||||||
|
case HTTP_CONN_FAILED:
|
||||||
|
_serverView.setError(getString(R.string.error_http_connection_failed));
|
||||||
|
_serverView.requestFocus();
|
||||||
|
break;
|
||||||
|
case CONN_FAILED:
|
||||||
|
_serverView.setError(getString(R.string.error_connection_failed));
|
||||||
|
_serverView.requestFocus();
|
||||||
|
break;
|
||||||
|
case INVALID_LOGIN:
|
||||||
|
_passwordView.setError(getString(R.string.error_invalid_login));
|
||||||
|
_passwordView.requestFocus();
|
||||||
|
break;
|
||||||
|
case UNKNOWN_ERROR:
|
||||||
|
_serverView.setError("UNK");
|
||||||
|
_serverView.requestFocus();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCancelled() {
|
||||||
|
mAuthTask = null;
|
||||||
|
showProgress(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Uri _serverURI;
|
||||||
|
private final String _login;
|
||||||
|
private final String _password;
|
||||||
|
private LoginReturnCode _returnCode;
|
||||||
|
|
||||||
|
public static final String PARAM_AUTHTOKEN_TYPE = "auth.token";
|
||||||
|
public static final String PARAM_CREATE = "create";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,196 @@
|
|||||||
|
package fr.unix_experience.owncloud_sms.authenticators;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import org.apache.commons.httpclient.HttpException;
|
||||||
|
import org.apache.commons.httpclient.methods.GetMethod;
|
||||||
|
import org.apache.http.HttpStatus;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import com.owncloud.android.lib.common.OwnCloudClient;
|
||||||
|
|
||||||
|
import fr.unix_experience.owncloud_sms.activities.LoginActivity;
|
||||||
|
import fr.unix_experience.owncloud_sms.enums.LoginReturnCode;
|
||||||
|
import android.accounts.AbstractAccountAuthenticator;
|
||||||
|
import android.accounts.Account;
|
||||||
|
import android.accounts.AccountAuthenticatorResponse;
|
||||||
|
import android.accounts.AccountManager;
|
||||||
|
import android.accounts.NetworkErrorException;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
public class OwnCloudAuthenticator extends AbstractAccountAuthenticator {
|
||||||
|
// Simple constructor
|
||||||
|
public OwnCloudAuthenticator(Context context) {
|
||||||
|
super(context);
|
||||||
|
_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bundle editProperties(AccountAuthenticatorResponse response,
|
||||||
|
String accountType) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bundle addAccount(AccountAuthenticatorResponse response,
|
||||||
|
String accountType, String authTokenType,
|
||||||
|
String[] requiredFeatures, Bundle options)
|
||||||
|
throws NetworkErrorException {
|
||||||
|
final Bundle result;
|
||||||
|
final Intent intent;
|
||||||
|
|
||||||
|
intent = new Intent(_context, LoginActivity.class);
|
||||||
|
|
||||||
|
result = new Bundle();
|
||||||
|
result.putParcelable(AccountManager.KEY_INTENT, intent);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bundle confirmCredentials(AccountAuthenticatorResponse response,
|
||||||
|
Account account, Bundle options) throws NetworkErrorException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bundle getAuthToken(AccountAuthenticatorResponse response,
|
||||||
|
Account account, String authTokenType, Bundle options)
|
||||||
|
throws NetworkErrorException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAuthTokenLabel(String authTokenType) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bundle updateCredentials(AccountAuthenticatorResponse response,
|
||||||
|
Account account, String authTokenType, Bundle options)
|
||||||
|
throws NetworkErrorException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bundle hasFeatures(AccountAuthenticatorResponse response,
|
||||||
|
Account account, String[] features) throws NetworkErrorException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return codes
|
||||||
|
* 1: invalid address
|
||||||
|
* 2: HTTP failed
|
||||||
|
* 3: connexion failed
|
||||||
|
* 4: invalid login
|
||||||
|
* 5: unknown error
|
||||||
|
*/
|
||||||
|
public LoginReturnCode testCredentials() {
|
||||||
|
LoginReturnCode bRet = LoginReturnCode.OK;
|
||||||
|
GetMethod get = null;
|
||||||
|
int status = -1;
|
||||||
|
|
||||||
|
try {
|
||||||
|
get = new GetMethod(_client.getBaseUri() + "/index.php/ocs/cloud/user?format=json");
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
return LoginReturnCode.INVALID_ADDR;
|
||||||
|
}
|
||||||
|
|
||||||
|
get.addRequestHeader("OCS-APIREQUEST", "true");
|
||||||
|
|
||||||
|
try {
|
||||||
|
status = _client.executeMethod(get);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
return LoginReturnCode.INVALID_ADDR;
|
||||||
|
} catch (HttpException e) {
|
||||||
|
return LoginReturnCode.HTTP_CONN_FAILED;
|
||||||
|
} catch (IOException e) {
|
||||||
|
return LoginReturnCode.CONN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if(isSuccess(status)) {
|
||||||
|
String response = get.getResponseBodyAsString();
|
||||||
|
Log.d(TAG, "Successful response: " + response);
|
||||||
|
|
||||||
|
// Parse the response
|
||||||
|
JSONObject respJSON = new JSONObject(response);
|
||||||
|
JSONObject respOCS = respJSON.getJSONObject(NODE_OCS);
|
||||||
|
JSONObject respData = respOCS.getJSONObject(NODE_DATA);
|
||||||
|
String id = respData.getString(NODE_ID);
|
||||||
|
String displayName = respData.getString(NODE_DISPLAY_NAME);
|
||||||
|
String email = respData.getString(NODE_EMAIL);
|
||||||
|
|
||||||
|
Log.d(TAG, "*** Parsed user information: " + id + " - " + displayName + " - " + email);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
String response = get.getResponseBodyAsString();
|
||||||
|
Log.e(TAG, "Failed response while getting user information ");
|
||||||
|
if (response != null) {
|
||||||
|
Log.e(TAG, "*** status code: " + status + " ; response message: " + response);
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "*** status code: " + status);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status == 401) {
|
||||||
|
bRet = LoginReturnCode.INVALID_LOGIN;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bRet = LoginReturnCode.UNKNOWN_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Exception while getting OC user information", e);
|
||||||
|
bRet = LoginReturnCode.UNKNOWN_ERROR;
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
get.releaseConnection();
|
||||||
|
}
|
||||||
|
return bRet;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSuccess(int status) {
|
||||||
|
return (status == HttpStatus.SC_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClient(OwnCloudClient oc) {
|
||||||
|
_client = oc;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Context _context;
|
||||||
|
private OwnCloudClient _client;
|
||||||
|
|
||||||
|
private static final String TAG = OwnCloudAuthenticator.class.getSimpleName();
|
||||||
|
|
||||||
|
private static final String NODE_OCS = "ocs";
|
||||||
|
private static final String NODE_DATA = "data";
|
||||||
|
private static final String NODE_ID = "id";
|
||||||
|
private static final String NODE_DISPLAY_NAME= "display-name";
|
||||||
|
private static final String NODE_EMAIL= "email";
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
package fr.unix_experience.owncloud_sms.broadcast_receivers;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import fr.unix_experience.owncloud_sms.observers.SmsObserver;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
public class IncomingSms extends BroadcastReceiver {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
launchSmsObserver(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void launchSmsObserver(Context context) {
|
||||||
|
if (_mboxObserver == null) {
|
||||||
|
Log.d(TAG,"_mboxObserver == null");
|
||||||
|
_mboxObserver = new SmsObserver(new Handler(), context);
|
||||||
|
context.getContentResolver().
|
||||||
|
registerContentObserver(Uri.parse("content://sms"), true, _mboxObserver);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SmsObserver _mboxObserver;
|
||||||
|
|
||||||
|
private static final String TAG = IncomingSms.class.getSimpleName();
|
||||||
|
}
|
@ -0,0 +1,352 @@
|
|||||||
|
package fr.unix_experience.owncloud_sms.engine;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.ConnectException;
|
||||||
|
|
||||||
|
import org.apache.commons.httpclient.HttpException;
|
||||||
|
import org.apache.commons.httpclient.HttpMethod;
|
||||||
|
import org.apache.commons.httpclient.methods.GetMethod;
|
||||||
|
import org.apache.commons.httpclient.methods.PostMethod;
|
||||||
|
import org.apache.commons.httpclient.methods.StringRequestEntity;
|
||||||
|
import org.apache.http.HttpStatus;
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.owncloud.android.lib.common.OwnCloudClient;
|
||||||
|
import com.owncloud.android.lib.common.OwnCloudClientFactory;
|
||||||
|
import com.owncloud.android.lib.common.OwnCloudCredentialsFactory;
|
||||||
|
|
||||||
|
import fr.unix_experience.owncloud_sms.R;
|
||||||
|
import fr.unix_experience.owncloud_sms.enums.OCSyncErrorType;
|
||||||
|
import fr.unix_experience.owncloud_sms.exceptions.OCSyncException;
|
||||||
|
|
||||||
|
public class OCSMSOwnCloudClient {
|
||||||
|
|
||||||
|
public OCSMSOwnCloudClient(Context context, Uri serverURI, String accountName, String accountPassword) {
|
||||||
|
_context = context;
|
||||||
|
|
||||||
|
_ocClient = OwnCloudClientFactory.createOwnCloudClient(
|
||||||
|
serverURI, _context, true);
|
||||||
|
|
||||||
|
// Set basic credentials
|
||||||
|
_ocClient.setCredentials(
|
||||||
|
OwnCloudCredentialsFactory.newBasicCredentials(accountName, accountPassword)
|
||||||
|
);
|
||||||
|
|
||||||
|
_serverAPIVersion = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getServerAPIVersion() throws OCSyncException {
|
||||||
|
GetMethod get = createGetVersionRequest();
|
||||||
|
JSONObject obj = doHttpRequest(get, true);
|
||||||
|
if (obj == null) {
|
||||||
|
// Return default version
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
_serverAPIVersion = obj.getInt("version");
|
||||||
|
}
|
||||||
|
catch (JSONException e) {
|
||||||
|
Log.e(TAG, "No version received from server, assuming version 1", e);
|
||||||
|
_serverAPIVersion = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _serverAPIVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doPushRequest(JSONArray smsList) throws OCSyncException {
|
||||||
|
/**
|
||||||
|
* If we need other API push, set it here
|
||||||
|
*/
|
||||||
|
switch (_serverAPIVersion) {
|
||||||
|
case 1:
|
||||||
|
default: doPushRequestV1(smsList); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doPushRequestV1(JSONArray smsList) throws OCSyncException {
|
||||||
|
if (smsList == null) {
|
||||||
|
GetMethod get = createGetSmsIdListRequest();
|
||||||
|
JSONObject smsGetObj = doHttpRequest(get);
|
||||||
|
if (smsGetObj == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject smsBoxes = new JSONObject();
|
||||||
|
JSONArray inboxSmsList = null, sentSmsList = null, draftsSmsList = null;
|
||||||
|
try {
|
||||||
|
smsBoxes = smsGetObj.getJSONObject("smslist");
|
||||||
|
} catch (JSONException e) {
|
||||||
|
try {
|
||||||
|
smsGetObj.getJSONArray("smslist");
|
||||||
|
} catch (JSONException e2) {
|
||||||
|
Log.e(TAG, "Invalid datas received from server (doPushRequest, get SMS list)", e);
|
||||||
|
throw new OCSyncException(R.string.err_sync_get_smslist, OCSyncErrorType.PARSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
inboxSmsList = smsBoxes.getJSONArray("inbox");
|
||||||
|
} catch (JSONException e) {
|
||||||
|
Log.d(TAG, "No inbox Sms received from server (doPushRequest, get SMS list)");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
sentSmsList = smsBoxes.getJSONArray("sent");
|
||||||
|
} catch (JSONException e) {
|
||||||
|
Log.d(TAG, "No sent Sms received from server (doPushRequest, get SMS list)");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
draftsSmsList = smsBoxes.getJSONArray("drafts");
|
||||||
|
} catch (JSONException e) {
|
||||||
|
Log.d(TAG, "No drafts Sms received from server (doPushRequest, get SMS list)");
|
||||||
|
}
|
||||||
|
|
||||||
|
SmsFetcher fetcher = new SmsFetcher(_context);
|
||||||
|
fetcher.setExistingInboxMessages(inboxSmsList);
|
||||||
|
fetcher.setExistingSentMessages(sentSmsList);
|
||||||
|
fetcher.setExistingDraftsMessages(draftsSmsList);
|
||||||
|
|
||||||
|
smsList = fetcher.getJSONMessages();
|
||||||
|
}
|
||||||
|
|
||||||
|
PostMethod post = createPushRequest(smsList);
|
||||||
|
if (post == null) {
|
||||||
|
Log.e(TAG,"Push request for POST is null");
|
||||||
|
throw new OCSyncException(R.string.err_sync_craft_http_request, OCSyncErrorType.IO);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject obj = doHttpRequest(post);
|
||||||
|
if (obj == null) {
|
||||||
|
Log.e(TAG,"Request failed. It doesn't return a valid JSON Object");
|
||||||
|
throw new OCSyncException(R.string.err_sync_push_request, OCSyncErrorType.IO);
|
||||||
|
}
|
||||||
|
|
||||||
|
Boolean pushStatus;
|
||||||
|
String pushMessage;
|
||||||
|
try {
|
||||||
|
pushStatus = obj.getBoolean("status");
|
||||||
|
pushMessage = obj.getString("msg");
|
||||||
|
}
|
||||||
|
catch (JSONException e) {
|
||||||
|
Log.e(TAG, "Invalid datas received from server", e);
|
||||||
|
throw new OCSyncException(R.string.err_sync_push_request_resp, OCSyncErrorType.PARSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.d(TAG, "SMS Push request said: status " + pushStatus + " - " + pushMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GetMethod createGetVersionRequest() {
|
||||||
|
return createGetRequest(OC_GET_VERSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GetMethod createGetSmsIdListRequest() {
|
||||||
|
return createGetRequest(OC_GET_ALL_SMS_IDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GetMethod createGetSmsIdListWithStateRequest() {
|
||||||
|
return createGetRequest(OC_GET_ALL_SMS_IDS_WITH_STATUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private GetMethod createGetRequest(String oc_call) {
|
||||||
|
GetMethod get = new GetMethod(_ocClient.getBaseUri() + oc_call);
|
||||||
|
get.addRequestHeader("OCS-APIREQUEST", "true");
|
||||||
|
return get;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PostMethod createPushRequest() throws OCSyncException {
|
||||||
|
SmsFetcher fetcher = new SmsFetcher(_context);
|
||||||
|
JSONArray smsList = fetcher.getJSONMessages();
|
||||||
|
return createPushRequest(smsList);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PostMethod createPushRequest(JSONArray smsList) throws OCSyncException {
|
||||||
|
JSONObject obj = createPushJSONObject(smsList);
|
||||||
|
if (obj == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringRequestEntity ent = createJSONRequestEntity(obj);
|
||||||
|
if (ent == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
PostMethod post = new PostMethod(_ocClient.getBaseUri() + OC_PUSH_ROUTE);
|
||||||
|
post.addRequestHeader("OCS-APIREQUEST", "true");
|
||||||
|
post.setRequestEntity(ent);
|
||||||
|
|
||||||
|
return post;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JSONObject createPushJSONObject(JSONArray smsList) throws OCSyncException {
|
||||||
|
if (smsList == null) {
|
||||||
|
Log.e(TAG,"NULL SMS List");
|
||||||
|
throw new OCSyncException(R.string.err_sync_create_json_null_smslist, OCSyncErrorType.IO);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject reqJSON = new JSONObject();
|
||||||
|
|
||||||
|
try {
|
||||||
|
reqJSON.put("smsDatas", smsList);
|
||||||
|
reqJSON.put("smsCount", smsList == null ? 0 : smsList.length());
|
||||||
|
} catch (JSONException e) {
|
||||||
|
Log.e(TAG,"JSON Exception when creating JSON request object");
|
||||||
|
throw new OCSyncException(R.string.err_sync_create_json_put_smslist, OCSyncErrorType.PARSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return reqJSON;
|
||||||
|
}
|
||||||
|
|
||||||
|
private StringRequestEntity createJSONRequestEntity(JSONObject obj) throws OCSyncException {
|
||||||
|
StringRequestEntity requestEntity;
|
||||||
|
try {
|
||||||
|
requestEntity = new StringRequestEntity(
|
||||||
|
obj.toString(),
|
||||||
|
"application/json",
|
||||||
|
"UTF-8");
|
||||||
|
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
Log.e(TAG,"Unsupported encoding when generating request");
|
||||||
|
throw new OCSyncException(R.string.err_sync_create_json_request_encoding, OCSyncErrorType.PARSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return requestEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JSONObject doHttpRequest(HttpMethod req) throws OCSyncException {
|
||||||
|
return doHttpRequest(req, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// skipError permit to skip invalid JSON datas
|
||||||
|
private JSONObject doHttpRequest(HttpMethod req, Boolean skipError) throws OCSyncException {
|
||||||
|
JSONObject respJSON = null;
|
||||||
|
int status = 0;
|
||||||
|
|
||||||
|
// We try maximumHttpReqTries because sometimes network is slow or unstable
|
||||||
|
int tryNb = 0;
|
||||||
|
|
||||||
|
while (tryNb < maximumHttpReqTries) {
|
||||||
|
tryNb++;
|
||||||
|
|
||||||
|
try {
|
||||||
|
status = _ocClient.executeMethod(req);
|
||||||
|
|
||||||
|
Log.d(TAG, "HTTP Request done at try " + tryNb);
|
||||||
|
|
||||||
|
// Force loop exit
|
||||||
|
tryNb = maximumHttpReqTries;
|
||||||
|
} catch (ConnectException e) {
|
||||||
|
Log.e(TAG, "Unable to perform a connection to ownCloud instance", e);
|
||||||
|
|
||||||
|
// If it's the last try
|
||||||
|
if (tryNb == maximumHttpReqTries) {
|
||||||
|
req.releaseConnection();
|
||||||
|
throw new OCSyncException(R.string.err_sync_http_request_connect, OCSyncErrorType.IO);
|
||||||
|
}
|
||||||
|
} catch (HttpException e) {
|
||||||
|
Log.e(TAG, "Unable to perform a connection to ownCloud instance", e);
|
||||||
|
|
||||||
|
// If it's the last try
|
||||||
|
if (tryNb == maximumHttpReqTries) {
|
||||||
|
req.releaseConnection();
|
||||||
|
throw new OCSyncException(R.string.err_sync_http_request_httpexception, OCSyncErrorType.IO);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "Unable to perform a connection to ownCloud instance", e);
|
||||||
|
|
||||||
|
// If it's the last try
|
||||||
|
if (tryNb == maximumHttpReqTries) {
|
||||||
|
req.releaseConnection();
|
||||||
|
throw new OCSyncException(R.string.err_sync_http_request_ioexception, OCSyncErrorType.IO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(status == HttpStatus.SC_OK) {
|
||||||
|
String response = null;
|
||||||
|
try {
|
||||||
|
response = req.getResponseBodyAsString();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "Unable to parse server response", e);
|
||||||
|
throw new OCSyncException(R.string.err_sync_http_request_resp, OCSyncErrorType.IO);
|
||||||
|
}
|
||||||
|
//Log.d(TAG, "Successful response: " + response);
|
||||||
|
|
||||||
|
// Parse the response
|
||||||
|
try {
|
||||||
|
respJSON = new JSONObject(response);
|
||||||
|
} catch (JSONException e) {
|
||||||
|
if (skipError == false) {
|
||||||
|
Log.e(TAG, "Unable to parse server response", e);
|
||||||
|
throw new OCSyncException(R.string.err_sync_http_request_parse_resp, OCSyncErrorType.PARSE);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (status == HttpStatus.SC_FORBIDDEN) {
|
||||||
|
// Authentication failed
|
||||||
|
throw new OCSyncException(R.string.err_sync_auth_failed, OCSyncErrorType.AUTH);
|
||||||
|
} else {
|
||||||
|
// Unk error
|
||||||
|
String response = null;
|
||||||
|
try {
|
||||||
|
response = req.getResponseBodyAsString();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "Unable to parse server response", e);
|
||||||
|
throw new OCSyncException(R.string.err_sync_http_request_resp, OCSyncErrorType.PARSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.e(TAG, "Server set unhandled HTTP return code " + status);
|
||||||
|
if (response != null) {
|
||||||
|
Log.e(TAG, "Status code: " + status + ". Response message: " + response);
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "Status code: " + status);
|
||||||
|
}
|
||||||
|
throw new OCSyncException(R.string.err_sync_http_request_returncode_unhandled, OCSyncErrorType.SERVER_ERROR);
|
||||||
|
}
|
||||||
|
return respJSON;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OwnCloudClient getOCClient() { return _ocClient; }
|
||||||
|
|
||||||
|
private static int maximumHttpReqTries = 3;
|
||||||
|
|
||||||
|
private OwnCloudClient _ocClient;
|
||||||
|
private Context _context;
|
||||||
|
|
||||||
|
private Integer _serverAPIVersion;
|
||||||
|
|
||||||
|
private static String OC_GET_VERSION = "/index.php/apps/ocsms/get/apiversion?format=json";
|
||||||
|
private static String OC_GET_ALL_SMS_IDS = "/index.php/apps/ocsms/get/smsidlist?format=json";
|
||||||
|
private static String OC_GET_ALL_SMS_IDS_WITH_STATUS = "/index.php/apps/ocsms/get/smsidstate?format=json";
|
||||||
|
private static String OC_PUSH_ROUTE = "/index.php/apps/ocsms/push?format=json";
|
||||||
|
|
||||||
|
private static final String TAG = OCSMSOwnCloudClient.class.getSimpleName();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
248
src/fr/unix_experience/owncloud_sms/engine/SmsFetcher.java
Normal file
248
src/fr/unix_experience/owncloud_sms/engine/SmsFetcher.java
Normal file
@ -0,0 +1,248 @@
|
|||||||
|
package fr.unix_experience.owncloud_sms.engine;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import fr.unix_experience.owncloud_sms.enums.MailboxID;
|
||||||
|
import fr.unix_experience.owncloud_sms.providers.SmsDataProvider;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
public class SmsFetcher {
|
||||||
|
public SmsFetcher(Context ct) {
|
||||||
|
_context = ct;
|
||||||
|
|
||||||
|
_existingInboxMessages = null;
|
||||||
|
_existingSentMessages = null;
|
||||||
|
_existingDraftsMessages = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JSONArray getJSONMessages() {
|
||||||
|
_jsonTempDatas = new JSONArray();
|
||||||
|
|
||||||
|
getInboxMessages(true);
|
||||||
|
getSentMessages(true);
|
||||||
|
getDraftMessages(true);
|
||||||
|
|
||||||
|
JSONArray result = _jsonTempDatas;
|
||||||
|
|
||||||
|
// Empty the buffer
|
||||||
|
_jsonTempDatas = new JSONArray();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JSONArray getInboxMessages(Boolean toTempBuffer) {
|
||||||
|
return getMailboxMessages("content://sms/inbox", toTempBuffer, MailboxID.INBOX);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JSONArray getSentMessages(Boolean toTempBuffer) {
|
||||||
|
return getMailboxMessages("content://sms/sent", toTempBuffer, MailboxID.SENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JSONArray getDraftMessages(Boolean toTempBuffer) {
|
||||||
|
return getMailboxMessages("content://sms/drafts", toTempBuffer, MailboxID.DRAFTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private JSONArray getMailboxMessages(String _mb, Boolean toTempBuffer, MailboxID _mbID) {
|
||||||
|
if (_context == null || _mb.length() == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch Sent SMS Message from Built-in Content Provider
|
||||||
|
Cursor c = (new SmsDataProvider(_context)).query(_mb);
|
||||||
|
|
||||||
|
// We create a list of strings to store results
|
||||||
|
JSONArray results = new JSONArray();
|
||||||
|
|
||||||
|
// Reading mailbox
|
||||||
|
if (c != null && c.getCount() > 0) {
|
||||||
|
c.moveToFirst();
|
||||||
|
do {
|
||||||
|
JSONObject entry = new JSONObject();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Reading each mail element
|
||||||
|
int msgId = -1;
|
||||||
|
for(int idx=0;idx<c.getColumnCount();idx++) {
|
||||||
|
String colName = c.getColumnName(idx);
|
||||||
|
|
||||||
|
// Id column is must be an integer
|
||||||
|
if (colName.equals(new String("_id")) ||
|
||||||
|
colName.equals(new String("type"))) {
|
||||||
|
entry.put(colName, c.getInt(idx));
|
||||||
|
|
||||||
|
// bufferize Id for future use
|
||||||
|
if (colName.equals(new String("_id"))) {
|
||||||
|
msgId = c.getInt(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Seen and read must be pseudo boolean
|
||||||
|
else if (colName.equals(new String("read")) ||
|
||||||
|
colName.equals(new String("seen"))) {
|
||||||
|
entry.put(colName, c.getInt(idx) > 0 ? "true" : "false");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
entry.put(colName, c.getString(idx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mailbox ID is required by server
|
||||||
|
entry.put("mbox", _mbID.ordinal());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use the existing lists to verify if mail needs to be buffered
|
||||||
|
* It's useful to decrease data use
|
||||||
|
*/
|
||||||
|
if (_mbID == MailboxID.INBOX && isAnExistingInboxMessage(msgId) == false ||
|
||||||
|
_mbID == MailboxID.SENT && isAnExistingSentMessage(msgId) == false ||
|
||||||
|
_mbID == MailboxID.DRAFTS && isAnExistingDraftsMessage(msgId) == false) {
|
||||||
|
if (toTempBuffer) {
|
||||||
|
_jsonTempDatas.put(entry);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
results.put(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (JSONException e) {
|
||||||
|
Log.e(TAG, "JSON Exception when reading SMS Mailbox", e);
|
||||||
|
c.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while(c.moveToNext());
|
||||||
|
|
||||||
|
Log.d(TAG, c.getCount() + " messages read from " +_mb);
|
||||||
|
|
||||||
|
c.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JSONArray getLastMessage(String _mb) {
|
||||||
|
if (_context == null || _mb.length() == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch Sent SMS Message from Built-in Content Provider
|
||||||
|
Cursor c = (new SmsDataProvider(_context)).query(_mb);
|
||||||
|
|
||||||
|
c.moveToNext();
|
||||||
|
|
||||||
|
// We create a list of strings to store results
|
||||||
|
JSONArray results = new JSONArray();
|
||||||
|
|
||||||
|
JSONObject entry = new JSONObject();
|
||||||
|
|
||||||
|
try {
|
||||||
|
for(int idx=0;idx<c.getColumnCount();idx++) {
|
||||||
|
String colName = c.getColumnName(idx);
|
||||||
|
|
||||||
|
// Id column is must be an integer
|
||||||
|
if (colName.equals(new String("_id")) ||
|
||||||
|
colName.equals(new String("type"))) {
|
||||||
|
entry.put(colName, c.getInt(idx));
|
||||||
|
|
||||||
|
// bufferize Id for future use
|
||||||
|
if (colName.equals(new String("_id"))) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Seen and read must be pseudo boolean
|
||||||
|
else if (colName.equals(new String("read")) ||
|
||||||
|
colName.equals(new String("seen"))) {
|
||||||
|
entry.put(colName, c.getInt(idx) > 0 ? "true" : "false");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
entry.put(colName, c.getString(idx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mailbox ID is required by server
|
||||||
|
switch (entry.getInt("type")) {
|
||||||
|
case 1: entry.put("mbox", MailboxID.INBOX.ordinal()); break;
|
||||||
|
case 2: entry.put("mbox", MailboxID.SENT.ordinal()); break;
|
||||||
|
case 3: entry.put("mbox", MailboxID.DRAFTS.ordinal()); break;
|
||||||
|
}
|
||||||
|
results.put(entry);
|
||||||
|
} catch (JSONException e) {
|
||||||
|
Log.e(TAG, "JSON Exception when reading SMS Mailbox", e);
|
||||||
|
c.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
c.close();
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isAnExistingInboxMessage(int msgId) {
|
||||||
|
return isExistingMessage(_existingInboxMessages, msgId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isAnExistingSentMessage(int msgId) {
|
||||||
|
return isExistingMessage(_existingSentMessages, msgId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isAnExistingDraftsMessage(int msgId) {
|
||||||
|
return isExistingMessage(_existingDraftsMessages, msgId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isExistingMessage(JSONArray msgList, int msgId) {
|
||||||
|
if (msgList == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int len = msgList.length();
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
try {
|
||||||
|
if (msgList.getInt(i) == msgId) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (JSONException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExistingInboxMessages(JSONArray inboxMessages) {
|
||||||
|
_existingInboxMessages = inboxMessages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExistingSentMessages(JSONArray sentMessages) {
|
||||||
|
_existingSentMessages = sentMessages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExistingDraftsMessages(JSONArray draftMessages) {
|
||||||
|
_existingDraftsMessages = draftMessages;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Context _context;
|
||||||
|
private JSONArray _jsonTempDatas;
|
||||||
|
private JSONArray _existingInboxMessages;
|
||||||
|
private JSONArray _existingSentMessages;
|
||||||
|
private JSONArray _existingDraftsMessages;
|
||||||
|
|
||||||
|
private static final String TAG = SmsFetcher.class.getSimpleName();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package fr.unix_experience.owncloud_sms.enums;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, 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 enum OCSMSNotificationType {
|
||||||
|
SYNC,
|
||||||
|
SYNC_FAILED,
|
||||||
|
}
|
@ -1,5 +1,22 @@
|
|||||||
package fr.unix_experience.owncloud_sms.exceptions;
|
package fr.unix_experience.owncloud_sms.exceptions;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
import fr.unix_experience.owncloud_sms.enums.OCSyncErrorType;
|
import fr.unix_experience.owncloud_sms.enums.OCSyncErrorType;
|
||||||
|
|
||||||
public class OCSyncException extends Exception {
|
public class OCSyncException extends Exception {
|
||||||
|
@ -0,0 +1,98 @@
|
|||||||
|
package fr.unix_experience.owncloud_sms.observers;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
|
||||||
|
import fr.unix_experience.owncloud_sms.R;
|
||||||
|
import fr.unix_experience.owncloud_sms.engine.OCSMSOwnCloudClient;
|
||||||
|
import fr.unix_experience.owncloud_sms.engine.SmsFetcher;
|
||||||
|
import fr.unix_experience.owncloud_sms.exceptions.OCSyncException;
|
||||||
|
import android.accounts.Account;
|
||||||
|
import android.accounts.AccountManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.ContentObserver;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
public class SmsObserver extends ContentObserver {
|
||||||
|
|
||||||
|
public SmsObserver(Handler handler) {
|
||||||
|
super(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SmsObserver(Handler handler, Context ct) {
|
||||||
|
super(handler);
|
||||||
|
_context = ct;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onChange(boolean selfChange) {
|
||||||
|
super.onChange(selfChange);
|
||||||
|
Log.d(TAG, "onChange SmsObserver");
|
||||||
|
|
||||||
|
if (_accountMgr == null && _context != null) {
|
||||||
|
_accountMgr = AccountManager.get(_context);
|
||||||
|
}
|
||||||
|
String smsURI = "content://sms";
|
||||||
|
|
||||||
|
SmsFetcher sFetch = new SmsFetcher(_context);
|
||||||
|
JSONArray smsList = sFetch.getLastMessage(smsURI);
|
||||||
|
|
||||||
|
if (smsList != null) {
|
||||||
|
new SyncTask(smsList).execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SyncTask extends AsyncTask<Void, Void, Void>{
|
||||||
|
public SyncTask(JSONArray smsList) {
|
||||||
|
_smsList = smsList;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
protected Void doInBackground(Void... params) {
|
||||||
|
// Get ownCloud SMS account list
|
||||||
|
Account[] myAccountList = _accountMgr.getAccountsByType(_context.getString(R.string.account_type));
|
||||||
|
for (int i = 0; i < myAccountList.length; i++) {
|
||||||
|
Log.d(TAG, "int i = 0; i < myAccountList.length; i++" + myAccountList[i] + " SmsObserver");
|
||||||
|
Uri serverURI = Uri.parse(_accountMgr.getUserData(myAccountList[i], "ocURI"));
|
||||||
|
|
||||||
|
OCSMSOwnCloudClient _client = new OCSMSOwnCloudClient(_context,
|
||||||
|
serverURI, _accountMgr.getUserData(myAccountList[i], "ocLogin"),
|
||||||
|
_accountMgr.getPassword(myAccountList[i]));
|
||||||
|
|
||||||
|
try {
|
||||||
|
_client.doPushRequest(_smsList);
|
||||||
|
} catch (OCSyncException e) {
|
||||||
|
Log.e(TAG, _context.getString(e.getErrorId()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
private JSONArray _smsList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContext(Context context) {
|
||||||
|
_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Context _context;
|
||||||
|
private static AccountManager _accountMgr;
|
||||||
|
|
||||||
|
private static final String TAG = OCSMSOwnCloudClient.class.getSimpleName();
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
package fr.unix_experience.owncloud_sms.sync_adapters;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import fr.unix_experience.owncloud_sms.engine.OCSMSOwnCloudClient;
|
||||||
|
import fr.unix_experience.owncloud_sms.enums.OCSyncErrorType;
|
||||||
|
import fr.unix_experience.owncloud_sms.exceptions.OCSyncException;
|
||||||
|
import fr.unix_experience.owncloud_sms.notifications.OCSMSNotificationManager;
|
||||||
|
import android.accounts.Account;
|
||||||
|
import android.accounts.AccountManager;
|
||||||
|
import android.content.AbstractThreadedSyncAdapter;
|
||||||
|
import android.content.ContentProviderClient;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SyncResult;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
public class SmsSyncAdapter extends AbstractThreadedSyncAdapter {
|
||||||
|
|
||||||
|
public SmsSyncAdapter(Context context, boolean autoInitialize) {
|
||||||
|
super(context, autoInitialize);
|
||||||
|
_accountMgr = AccountManager.get(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPerformSync(Account account, Bundle extras, String authority,
|
||||||
|
ContentProviderClient provider, SyncResult syncResult) {
|
||||||
|
|
||||||
|
OCSMSNotificationManager nMgr = new OCSMSNotificationManager(getContext());
|
||||||
|
nMgr.setSyncProcessMsg();
|
||||||
|
|
||||||
|
// Create client
|
||||||
|
Uri serverURI = Uri.parse(_accountMgr.getUserData(account, "ocURI"));
|
||||||
|
|
||||||
|
OCSMSOwnCloudClient _client = new OCSMSOwnCloudClient(getContext(),
|
||||||
|
serverURI, _accountMgr.getUserData(account, "ocLogin"),
|
||||||
|
_accountMgr.getPassword(account));
|
||||||
|
|
||||||
|
try {
|
||||||
|
// getServerAPI version
|
||||||
|
Log.d(TAG,"Server API version: " + _client.getServerAPIVersion());
|
||||||
|
|
||||||
|
// and push datas
|
||||||
|
_client.doPushRequest(null);
|
||||||
|
} catch (OCSyncException e) {
|
||||||
|
nMgr.setSyncErrorMsg(getContext().getString(e.getErrorId()));
|
||||||
|
if (e.getErrorType() == OCSyncErrorType.IO) {
|
||||||
|
syncResult.stats.numIoExceptions++;
|
||||||
|
}
|
||||||
|
else if (e.getErrorType() == OCSyncErrorType.PARSE) {
|
||||||
|
syncResult.stats.numParseExceptions++;
|
||||||
|
}
|
||||||
|
else if (e.getErrorType() == OCSyncErrorType.AUTH) {
|
||||||
|
syncResult.stats.numAuthExceptions++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// UNHANDLED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nMgr.dropSyncProcessMsg();
|
||||||
|
}
|
||||||
|
|
||||||
|
private AccountManager _accountMgr;
|
||||||
|
|
||||||
|
private static final String TAG = SmsSyncAdapter.class.getSimpleName();
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user