mirror of
				https://github.com/nerzhul/ownCloud-SMS-App.git
				synced 2025-10-31 02:17:53 +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; | ||||
| 
 | ||||
| /* | ||||
|  *  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; | ||||
| 
 | ||||
| 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