1
0
mirror of https://github.com/nerzhul/ownCloud-SMS-App.git synced 2025-06-13 10:56:43 +00:00

Compare commits

..

No commits in common. "master" and "0.17.1" have entirely different histories.

328 changed files with 3306 additions and 21346 deletions

9
.gitignore vendored
View File

@ -1,9 +0,0 @@
/bin/
ownCloudSMS.iml
/build/
ownCloudSMS-release.apk
lint.xml
.gradle/
.idea/
local.properties
ownCloud-SMS-App.iml

View File

@ -1,231 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectCodeStyleSettingsManager">
<option name="PER_PROJECT_SETTINGS">
<value>
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
<option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
<value />
</option>
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="android" withSubpackages="true" static="false" />
<emptyLine />
<package name="com" withSubpackages="true" static="false" />
<emptyLine />
<package name="junit" withSubpackages="true" static="false" />
<emptyLine />
<package name="net" withSubpackages="true" static="false" />
<emptyLine />
<package name="org" withSubpackages="true" static="false" />
<emptyLine />
<package name="java" withSubpackages="true" static="false" />
<emptyLine />
<package name="javax" withSubpackages="true" static="false" />
<emptyLine />
<package name="" withSubpackages="true" static="false" />
<emptyLine />
<package name="" withSubpackages="true" static="true" />
<emptyLine />
</value>
</option>
<option name="RIGHT_MARGIN" value="100" />
<AndroidXmlCodeStyleSettings>
<option name="USE_CUSTOM_SETTINGS" value="true" />
</AndroidXmlCodeStyleSettings>
<Objective-C-extensions>
<option name="GENERATE_INSTANCE_VARIABLES_FOR_PROPERTIES" value="ASK" />
<option name="RELEASE_STYLE" value="IVAR" />
<option name="TYPE_QUALIFIERS_PLACEMENT" value="BEFORE" />
<file>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
</file>
<class>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
</class>
<extensions>
<pair source="cpp" header="h" />
<pair source="c" header="h" />
</extensions>
</Objective-C-extensions>
<XML>
<option name="XML_KEEP_LINE_BREAKS" value="false" />
<option name="XML_ALIGN_ATTRIBUTES" value="false" />
<option name="XML_SPACE_INSIDE_EMPTY_TAG" value="true" />
</XML>
<codeStyleSettings language="XML">
<option name="FORCE_REARRANGE_MODE" value="1" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:name</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>name</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_width</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_height</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:width</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:height</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
</value>
</option>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default (1)" />
</component>
</project>

View File

@ -1,28 +0,0 @@
---
language: android
before_cache:
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
- rm -fr $HOME/.gradle/caches/*/plugin-resolution/
cache:
directories:
- $HOME/.gradle/caches/
- $HOME/.gradle/wrapper/
jdk:
- oraclejdk8
before_install:
- yes | sdkmanager "platforms;android-28"
android:
components:
- tools
- platform-tools
- extra
- build-tools-28.0.3
- android-28
licenses:
- 'android-sdk-license-.+'
- 'google-gdk-license-.+'
- 'android-sdk-preview-license-.+'
- 'android-.*'

View File

@ -1,17 +0,0 @@
[main]
host = https://www.transifex.com
[o:nextcloud:p:nextcloud:r:android-sms]
file_filter = src/main/res/values-<lang>/strings.xml
source_file = src/main/res/values/strings.xml
source_lang = en
type = ANDROID
lang_map = ar_EG: ar-rEG, ar_KW: ar-rKW, da_DK: da-rDK, hu_HU: hu-rHU, lb_LU: lb-rLU, tzm_DZ: tzm-rDZ, ar_DZ: ar-rDZ, ar_SA: ar-rSA, arn_CL: arn-rCL, de_LI: de-rLI, fr_MC: fr-rMC, se_FI: se-rFI, ta_LK: ta-rLK, tt_RU: tt-rRU, xh_ZA: xh-rZA, co_FR: co-rFR, cy_GB: cy-rGB, en_SG: en-rSG, es_PA: es-rPA, es_UY: es-rUY, ku_IQ: ku-rIQ, rm_CH: rm-rCH, smj_SE: smj-rSE, sq_AL: sq-rAL, tr_TR: tr-rTR, uz_UZ: uz-rUZ, en_AU: en-rAU, ar_OM: ar-rOM, el_GR: el-rGR, es_EC: es-rEC, ha_NG: ha-rNG, hr_HR: hr-rHR, or_IN: or-rIN, pt_BR: pt-rBR, se_NO: se-rNO, am_ET: am-rET, en_US: en-rUS, es_PE: es-rPE, fa_IR: fa-rIR, fr_CA: fr-rCA, fy_NL: fy-rNL, hr_BA: hr-rBA, hy_AM: hy-rAM, lt_LT: lt-rLT, ar_SY: ar-rSY, ca_ES: ca-rES, en_JM: en-rJM, es_AR: es-rAR, es_PY: es-rPY, it_CH: it-rCH, kk_KZ: kk-rKZ, vi_VN: vi-rVN, es_MX: es-rMX, pt_PT: pt-rPT, uk_UA: uk-rUA, zh_CN.GB2312: zh-rBG, zu_ZA: zu-rZA, bs_BA: bs-rBA, is_IS: is-rIS, my_MM: my, quz_PE: quz-rPE, ur_PK: ur-rPK, ar_AE: ar-rAE, ar_LY: ar-rLY, ar_QA: ar-rQA, ja_JP: ja-rJP, nl_BE: nl-rBE, nso_ZA: nso-rZA, rw_RW: rw-rRW, sr_BA: sr-rBA, te_IN: te-rIN, de_AT: de-rAT, dv_MV: dv-rMV, ro_RO: ro-rRO, sv_SE: sv-rSE, fr_FR: fr-rFR, he_IL: he-rIL, ne_NP: ne-rNP, sms_FI: sms-rFI, ar_TN: ar-rTN, az_AZ: az-rAZ, de_LU: de-rLU, es_CO: es-rCO, es_NI: es-rNI, id_ID: id-rID, quz_BO: quz-rBO, sr@latin: sr-rSP, en_GB: en-rGB, es_PR: es-rPR, es_SV: es-rSV, kn_IN: kn-rIN, ar_MA: ar-rMA, bo_CN: bo-rCN, dsb_DE: dsb-rDE, ig_NG: ig-rNG, mn_CN: mn-rCN, moh_CA: moh-rCA, pa_IN: pa-rIN, ps_AF: ps-rAF, smn_FI: smn-rFI, zh_MO: zh-rMO, en@pirate: en-rpirate, gl_ES: gl-rES, th_TH: th-rTH, fr_BE: fr-rBE, nb_NO: nb-rNO, prs_AF: prs-rAF, qut_GT: qut-rGT, en_ZW: en-rZW, eu_ES: eu-rES, hsb_DE: hsb-rDE, lo_LA: lo-rLA, mk_MK: mk-rMK, sk_SK: sk-rSK, sma_SE: sma-rSE, zh_HK: zh-rHK, as_IN: as-rIN, en_MY: en-rMY, en_NZ: en-rNZ, es_GT: es-rGT, es_HN: es-rHN, hi_IN: hi-rIN, mt_MT: mt-rMT, oc_FR: oc-rFR, sa_IN: sa-rIN, tk_TM: tk-rTM, ba_RU: ba-rRU, be_BY: be-rBY, kl_GL: kl-rGL, lv_LV: lv-rLV, sah_RU: sah-rRU, yo_NG: yo-rNG, de_DE: de-rDE, es_VE: es-rVE, gd_GB: gd-rGB, ko_KR: ko-rKR, sl_SI: sl-rSI, ug_CN: ug-rCN, ar_YE: ar-rYE, en_IN: en-rIN, es_BO: es-rBO, fr_LU: fr-rLU, bn_BD: bn-rBD, bn_IN: bn-rIN, gu_IN: gu-rIN, mr_IN: mr-rIN, ar_IQ: ar-rIQ, en_CA: en-rCA, es_CR: es-rCR, es_ES: es-rES, ga_IE: ga-rIE, gsw_FR: gsw-rFR, mn_MN: mn-rMN, ru_RU: ru-rRU, sr_CS: sr-rCS, tg_TJ: tg-rTJ, bg_BG: bg-rBG, iu_CA: iu-rCA, nl_NL: nl-rNL, quz_EC: quz-rEC, sma_NO: sma-rNO, sv_FI: sv-rFI, en_IE: en-rIE, fr_CH: fr-rCH, zh_TW: zh-rTW, ar_LB: ar-rLB, br_FR: br-rFR, cs_CZ: cs-rCZ, en_BZ: en-rBZ, en_TT: en-rTT, et_EE: et-rEE, fi_FI: fi-rFI, ii_CN: ii-rCN, km_KH: km-rKH, kok_IN: kok-rIN, ml_IN: ml-rIN, se_SE: se-rSE, syr_SY: syr-rSY, af_ZA: af-rZA, en_ZA: en-rZA, es_CL: es-rCL, mi_NZ: mi-rNZ, smj_NO: smj-rNO, wo_SN: wo-rSN, ar_BH: ar-rBH, fo_FO: fo-rFO, ky_KG: ky-rKG, ms_BN: ms-rBN, nn_NO: nn-rNO, zh_SG: zh-rSG, ar_JO: ar-rJO, en_PH: en-rPH, es_DO: es-rDO, ms_MY: ms-rMY, pl_PL: pl-rPL, sr_RS: sr-rRS, zh_CN: zh-rCN, es_419: es-rUS, it_IT: it-rIT, ka_GE: ka-rGE, si_LK: si-rLK, tn_ZA: tn-rZA, de_CH: de-rCH, fil_PH: fil-rPH, sr_ME: sr-rME, sw_KE: sw-rKE, ta_IN: ta-rIN
[o:nextcloud:p:nextcloud:r:android-sms-playstore]
file_filter = src/main/res/values-<lang>/google_playstore_strings.xml
source_file = src/main/res/values/google_playstore_strings.xml
source_lang = en
type = ANDROID
lang_map = ka_GE: ka-rGE, kn_IN: kn-rIN, sr_CS: sr-rCS, tr_TR: tr-rTR, bs_BA: bs-rBA, es_VE: es-rVE, gd_GB: gd-rGB, es_BO: es-rBO, es_HN: es-rHN, es_PE: es-rPE, eu_ES: eu-rES, rw_RW: rw-rRW, de_CH: de-rCH, de_DE: de-rDE, en_GB: en-rGB, sk_SK: sk-rSK, smj_NO: smj-rNO, zu_ZA: zu-rZA, es_ES: es-rES, mn_MN: mn-rMN, sa_IN: sa-rIN, ta_LK: ta-rLK, uk_UA: uk-rUA, fil_PH: fil-rPH, hr_BA: hr-rBA, ml_IN: ml-rIN, tg_TJ: tg-rTJ, uz_UZ: uz-rUZ, ar_LY: ar-rLY, ar_YE: ar-rYE, my_MM: my, ar_KW: ar-rKW, en_ZW: en-rZW, es_PA: es-rPA, it_CH: it-rCH, ku_IQ: ku-rIQ, ar_AE: ar-rAE, ar_BH: ar-rBH, ar_DZ: ar-rDZ, prs_AF: prs-rAF, pt_BR: pt-rBR, ug_CN: ug-rCN, oc_FR: oc-rFR, sma_NO: sma-rNO, es_PY: es-rPY, ms_MY: ms-rMY, mt_MT: mt-rMT, es_CR: es-rCR, fr_BE: fr-rBE, or_IN: or-rIN, quz_EC: quz-rEC, sr@latin: sr-rSP, zh_HK: zh-rHK, ar_JO: ar-rJO, ar_MA: ar-rMA, bn_BD: bn-rBD, en_ZA: en-rZA, it_IT: it-rIT, ko_KR: ko-rKR, mk_MK: mk-rMK, bo_CN: bo-rCN, co_FR: co-rFR, dsb_DE: dsb-rDE, nl_NL: nl-rNL, sah_RU: sah-rRU, se_SE: se-rSE, zh_CN.GB2312: zh-rBG, zh_TW: zh-rTW, az_AZ: az-rAZ, cy_GB: cy-rGB, nb_NO: nb-rNO, es_UY: es-rUY, fo_FO: fo-rFO, ig_NG: ig-rNG, lo_LA: lo-rLA, mi_NZ: mi-rNZ, en_MY: en-rMY, en_TT: en-rTT, es_SV: es-rSV, nso_ZA: nso-rZA, th_TH: th-rTH, ms_BN: ms-rBN, en_SG: en-rSG, es_EC: es-rEC, id_ID: id-rID, nl_BE: nl-rBE, fr_CH: fr-rCH, hi_IN: hi-rIN, is_IS: is-rIS, en_AU: en-rAU, et_EE: et-rEE, pt_PT: pt-rPT, hy_AM: hy-rAM, lv_LV: lv-rLV, tk_TM: tk-rTM, ur_PK: ur-rPK, en_NZ: en-rNZ, es_DO: es-rDO, es_GT: es-rGT, sv_FI: sv-rFI, tzm_DZ: tzm-rDZ, vi_VN: vi-rVN, ar_OM: ar-rOM, fa_IR: fa-rIR, hu_HU: hu-rHU, de_AT: de-rAT, en_IN: en-rIN, iu_CA: iu-rCA, qut_GT: qut-rGT, smj_SE: smj-rSE, ar_SY: ar-rSY, ar_TN: ar-rTN, cs_CZ: cs-rCZ, te_IN: te-rIN, zh_MO: zh-rMO, quz_BO: quz-rBO, ta_IN: ta-rIN, zh_CN: zh-rCN, de_LI: de-rLI, en_BZ: en-rBZ, ga_IE: ga-rIE, fy_NL: fy-rNL, ha_NG: ha-rNG, kk_KZ: kk-rKZ, rm_CH: rm-rCH, ro_RO: ro-rRO, ar_SA: ar-rSA, en_PH: en-rPH, es_419: es-rUS, hr_HR: hr-rHR, pa_IN: pa-rIN, pl_PL: pl-rPL, sma_SE: sma-rSE, xh_ZA: xh-rZA, dv_MV: dv-rMV, fi_FI: fi-rFI, fr_FR: fr-rFR, zh_SG: zh-rSG, ne_NP: ne-rNP, da_DK: da-rDK, gu_IN: gu-rIN, km_KH: km-rKH, mr_IN: mr-rIN, smn_FI: smn-rFI, el_GR: el-rGR, es_CL: es-rCL, ky_KG: ky-rKG, ps_AF: ps-rAF, ru_RU: ru-rRU, sms_FI: sms-rFI, sq_AL: sq-rAL, arn_CL: arn-rCL, es_AR: es-rAR, fr_LU: fr-rLU, sr_ME: sr-rME, sr_RS: sr-rRS, sw_KE: sw-rKE, yo_NG: yo-rNG, be_BY: be-rBY, es_MX: es-rMX, es_NI: es-rNI, ii_CN: ii-rCN, si_LK: si-rLK, sl_SI: sl-rSI, tn_ZA: tn-rZA, ar_EG: ar-rEG, ar_IQ: ar-rIQ, fr_MC: fr-rMC, moh_CA: moh-rCA, se_NO: se-rNO, en_CA: en-rCA, fr_CA: fr-rCA, kl_GL: kl-rGL, en_IE: en-rIE, en_JM: en-rJM, gl_ES: gl-rES, hsb_DE: hsb-rDE, lb_LU: lb-rLU, af_ZA: af-rZA, ba_RU: ba-rRU, bn_IN: bn-rIN, sv_SE: sv-rSE, wo_SN: wo-rSN, es_CO: es-rCO, br_FR: br-rFR, he_IL: he-rIL, ja_JP: ja-rJP, lt_LT: lt-rLT, tt_RU: tt-rRU, ar_LB: ar-rLB, ar_QA: ar-rQA, as_IN: as-rIN, de_LU: de-rLU, es_PR: es-rPR, gsw_FR: gsw-rFR, kok_IN: kok-rIN, mn_CN: mn-rCN, am_ET: am-rET, bg_BG: bg-rBG, ca_ES: ca-rES, quz_PE: quz-rPE, se_FI: se-rFI, sr_BA: sr-rBA, syr_SY: syr-rSY, en_US: en-rUS, en@pirate: en-rpirate, nn_NO: nn-rNO

128
AndroidManifest.xml Normal file
View File

@ -0,0 +1,128 @@
<?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="19"
android:versionName="0.17.1">
<!-- From Android 4.0 to 5.0 -->
<uses-sdk
android:maxSdkVersion="22"
android:minSdkVersion="14"
android:targetSdkVersion="21" />
<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" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 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/OcSmsTheme" >
<!-- 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="@string/account_authority"
android:label="@string/pref_title_sync" >
</provider>
<!--
<service
android:name=".sync_adapters.SmsSlowSyncService"
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/slow_sync_adapter" />
</service>
<provider
android:name=".providers.SmsDataProvider"
android:label="@string/pref_title_slow_sync"
android:authorities="@string/slowsync_account_authority">
</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>
<receiver android:name=".broadcast_receivers.ConnectivityChanged" >
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
<activity
android:name=".activities.LoginActivity"
android:label="@string/title_activity_login" >
</activity>
<activity
android:name=".activities.GeneralSettingsActivity"
android:label="@string/title_activity_general_settings" >
</activity>
<activity
android:name=".activities.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".MainActivity2"
android:label="@string/title_activity_main_activity2" >
</activity>
</application>
</manifest>

View File

@ -1,20 +0,0 @@
# Overview
Nextcloud SMS is a free software developed by its contributors. This privacy policy
is intended to inform you about data gathered by this application."
# Information we collect
Only SMS and call log are collected by the application.
# Where information is sent.
Information is neither sent to Nextcloud team servers nor Nextcloud SMS team servers nor
any government nor another entity you don't want.
When you configure a Nextcloud account in the application, you agree with the Nextcloud
instance owner that your SMS and call log data will be stored in his infrastructure
under his responsibility.
We __don't__ recommend to use a public or a company Nextcloud instance account. Your privacy
must be under your control on your own Nextcloud instance.

View File

@ -1,45 +1,63 @@
# Nextcloud SMS (Android)
# ownCloud SMS Android Application Offical Repository
[![codebeat badge](https://codebeat.co/badges/df05cef7-6724-4a2f-b170-96ed1ab793f6)](https://codebeat.co/projects/github-com-nerzhul-owncloud-sms-app-master)
## Introduction
Nextcloud SMS app pushes your Android devices conversation into your Nextcloud instance, using [ocsms app](https://github.com/nerzhul/ocsms).
ownCloud SMS app push your Android devices conversation into your ownCloud instance, using ocsms app.
## :arrow_forward: Access
Android download link: https://play.google.com/store/apps/details?id=fr.unix_experience.owncloud_sms
[![Nextcloud Notes App on fdroid.org](https://camo.githubusercontent.com/7df0eafa4433fa4919a56f87c3d99cf81b68d01c/68747470733a2f2f662d64726f69642e6f72672f77696b692f696d616765732f632f63342f462d44726f69642d627574746f6e5f617661696c61626c652d6f6e2e706e67)](https://f-droid.org/repository/browse/?fdid=fr.unix_experience.owncloud_sms)
ocsms app sources are available here: https://github.com/nerzhul/ocsms/
ocsms app sources are available here: https://github.com/nextcloud/ocsms
## Application documentation
## :notebook: Application documentation
You can found application documentation here: https://github.com/nerzhul/ownCloud-SMS-App/wiki
You can find the application documentation here: https://github.com/nerzhul/ncsms-android/wiki
## Licence
## :link: Requirements
- [Nextcloud](https://nextcloud.com/) instance running
- [ocsms](https://github.com/nextcloud/ocsms) app enabled
ownCloud SMS Android Application licence is in reflexion, then sources are partial.
## :exclamation: Reporting issues
- App locales and layouts are under BSD 2 clause licence
- App DataProviders are under AGPLv3
- **Client:** https://github.com/nerzhul/ncsms-android/issues
- **Server:** https://github.com/nextcloud/ocsms/issues
## Contributions
## :rocket: Contributions
We are searching for translations in others langs
- We are searching for **translations** into others languages. To contribute please download `res/values/strings.xml` and `res/values/google_playstore_strings.xml` and provide a Pull Request with a translated version!
- You can also contribute by adding **patches** in Java code or cleanups.
- Application uses a [GoMobile AAR](https://gitlab.com/nerzhul/ncsmsgo) to have the best performance on phones with modern technologies like HTTP/2.0
To contribute please download res/values/strings.xml and res/values/google_playstore_strings.xml and give us a translated version !
### Build requirements
- gradle
You can also contribute by adding patches in Java code or cleanups.
## Requirements
- An ownCloud instance with ocsms app
## Issue template
Server
- ownCloud version: X.X.X
- PHP version: X.X
- HTTPd server: <apache|nginx...>
- HTTPS: <yes|no>
Client
- Android version: X.X.X
- Phone: <phone-model>
- ownCloud SMS app version: X.X.X
Please create your issues for the client here:
https://github.com/nerzhul/ownCloud-SMS-App/issues
And for the server app here:
https://github.com/nerzhul/ocsms/issues
## Developpers
You can found our continuous integration here: http://jenkins.unix-experience.fr/job/ownCloud%20SMS%20%28Android%29/
### Coding guidelines
- No empty lines at EOF
- No trailing whitespaces
## :notebook: License
Nextcloud SMS Android Application license is in reflexion, then sources are partial.
- App locales and layouts are under BSD 2 clause license
- App DataProviders are under AGPLv3

View File

@ -1,71 +0,0 @@
buildscript {
repositories {
mavenCentral()
jcenter()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
}
}
allprojects {
repositories {
jcenter()
google()
}
}
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
buildToolsVersion "28.0.3"
lintOptions {
abortOnError false
}
defaultConfig {
applicationId "fr.unix_experience.owncloud_sms"
versionCode 70
versionName "2.0.6"
minSdkVersion 16
targetSdkVersion 28
maxSdkVersion 28
ndk {
// Specifies the ABI configurations of your native
// libraries Gradle should build and package with your APK.
abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a',
'arm64-v8a', 'mips', 'mips64'
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
packagingOptions {
exclude 'META-INF/LICENSE.txt'
}
}
repositories {
maven {
url "https://jitpack.io"
}
mavenCentral()
google()
}
dependencies {
implementation 'com.android.support:support-v13:28.0.0'
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:design:28.0.0'
implementation 'in.srain.cube:ultra-ptr:1.0.11'
implementation 'com.github.dmytrodanylyk.android-process-button:library:1.0.4'
implementation 'com.android.support:support-v4:28.0.0'
implementation project(':ncsmsgo')
}

Binary file not shown.

View File

@ -1,6 +0,0 @@
#Sat Dec 22 18:14:31 CET 2018
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip

164
gradlew vendored
View File

@ -1,164 +0,0 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

90
gradlew.bat vendored
View File

@ -1,90 +0,0 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

BIN
ic_launcher-web.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

View File

@ -1,56 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
enable-background="new 0 0 595.275 311.111"
xml:space="preserve"
height="512"
width="512"
version="1.1"
y="0px"
x="0px"
id="svg2"
viewBox="0 0 512 512"
inkscape:version="0.91 r13725"
sodipodi:docname="ic_launcher.svg"><metadata
id="metadata10"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs8" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1148"
id="namedview6"
showgrid="false"
inkscape:zoom="0.73698733"
inkscape:cx="8.4791339"
inkscape:cy="91.823077"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg2" /><rect
rx="70"
ry="70"
height="448"
width="448"
y="32"
x="32"
id="rect4"
style="fill:#0082C9" /><path
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.25007507;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0"
d="m 122.44396,89.125042 c -18.45887,0 -33.318923,14.115008 -33.318923,31.647818 l 0,143.74017 c 0,17.53283 14.860053,31.64784 33.318923,31.64784 l 38.24891,0 152.52844,126.43415 -49.39316,-126.43415 125.72788,0 c 18.45889,0 33.31893,-14.11501 33.31893,-31.64784 l 0,-143.74017 c 0,-17.53281 -14.86004,-31.647818 -33.31893,-31.647818 z m 9.05472,27.207518 249.00265,0 c 9.08866,0 16.40549,5.85418 16.40549,13.12558 l 0,8.53918 c 0,7.27142 -7.31683,13.12389 -16.40549,13.12389 l -249.00265,0 c -9.08867,0 -16.40551,-5.85247 -16.40551,-13.12389 l 0,-8.53918 c 0,-7.2714 7.31684,-13.12558 16.40551,-13.12558 z m 0,60.50813 249.00265,0 c 9.08866,0 16.40549,5.85418 16.40549,13.12559 l 0,8.53748 c 0,7.27141 -7.31683,13.12559 -16.40549,13.12559 l -249.00265,0 c -9.08867,0 -16.40551,-5.85418 -16.40551,-13.12559 l 0,-8.53748 c 0,-7.27141 7.31684,-13.12559 16.40551,-13.12559 z m 0,60.01043 89.95439,0 c 9.08866,0 16.40548,7.9877 16.40548,15.25911 l 0,6.40397 c 0,7.27139 -7.31682,13.12558 -16.40548,13.12558 l -89.95439,0 c -9.08867,0 -16.40551,-5.85419 -16.40551,-13.12558 l 0,-6.40397 c 0,-7.27141 7.31684,-15.25911 16.40551,-15.25911 z"
id="rect3350"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssscccssssssssssssssssssssssssssssssss" /></svg>

Before

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -1,45 +0,0 @@
<!--
Thanks for reporting issues back to us!
To make it possible for us to help you please fill out below information carefully.
-->
### Steps to reproduce
1.
2.
3.
### Expected behaviour
Tell us what should happen
### Actual behaviour
Tell us what happens instead
### Server configuration
**Nextcloud version:**
**PHP version:**
**Webserver:**
**HTTPS:**
### Client configuration
**Android version:**
**Phone:**
**Nextcloud SMS app version:**
### Logs
```
Insert your log here
```
## Screenshots
<!--
Upload your screenshots here if any
-->

Binary file not shown.

3
lint.xml Normal file
View File

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<lint>
</lint>

View File

@ -1,2 +0,0 @@
configurations.maybeCreate("default")
artifacts.add("default", file('ncsmsgo.aar'))

Binary file not shown.

View File

@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id=":ncsmsgo" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle">
<configuration>
<option name="GRADLE_PROJECT_PATH" value=":ncsmsgo" />
</configuration>
</facet>
<facet type="java-gradle" name="Java-Gradle">
<configuration>
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" />
<option name="BUILDABLE" value="false" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
<excludeFolder url="file://$MODULE_DIR$/build" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -1,51 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
enable-background="new 0 0 595.275 311.111"
xml:space="preserve"
height="546.13336"
width="546.13336"
version="1.1"
y="0px"
x="0px"
id="svg2"
viewBox="0 0 512 512"
inkscape:version="0.92.1 r15371"
sodipodi:docname="notification_icon.svg"
inkscape:export-filename="C:\DEV\src\Android\Nextcloud\ownCloud-SMS-App\src\main\res\drawable-xxxhdpi\notification_icon.png"
inkscape:export-xdpi="16.879999"
inkscape:export-ydpi="16.879999"><metadata
id="metadata10"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs8" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1005"
id="namedview6"
showgrid="false"
inkscape:zoom="1.4739747"
inkscape:cx="140.31712"
inkscape:cy="253.09893"
inkscape:window-x="-9"
inkscape:window-y="-9"
inkscape:window-maximized="1"
inkscape:current-layer="svg2" /><path
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.30745259;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0"
d="m 76.647972,90.431718 c -24.788364,0 -44.743887,15.887432 -44.743887,35.621852 v 161.78969 c 0,19.73444 19.955523,35.62188 44.743887,35.62188 H 128.01232 L 332.84234,465.77569 266.5124,323.46514 h 168.83961 c 24.7884,0 44.7439,-15.88744 44.7439,-35.62188 V 126.05357 c 0,-19.73442 -19.9555,-35.621852 -44.7439,-35.621852 z M 88.80753,121.0557 h 334.38495 c 12.20514,0 22.03089,6.58929 22.03089,14.77376 v 9.61145 c 0,8.1845 -9.82575,14.77187 -22.03089,14.77187 H 88.80753 c -12.205149,0 -22.030913,-6.58737 -22.030913,-14.77187 v -9.61145 c 0,-8.18447 9.825764,-14.77376 22.030913,-14.77376 z m 0,68.10616 h 334.38495 c 12.20514,0 22.03089,6.5893 22.03089,14.77378 v 9.60954 c 0,8.18448 -9.82575,14.77377 -22.03089,14.77377 H 88.80753 c -12.205149,0 -22.030913,-6.58929 -22.030913,-14.77377 v -9.60954 c 0,-8.18448 9.825764,-14.77378 22.030913,-14.77378 z m 0,67.54597 h 120.79949 c 12.20514,0 22.03088,8.99072 22.03088,17.17521 v 7.20812 c 0,8.18446 -9.82574,14.77376 -22.03088,14.77376 H 88.80753 c -12.205149,0 -22.030913,-6.5893 -22.030913,-14.77376 v -7.20812 c 0,-8.18449 9.825764,-17.17521 22.030913,-17.17521 z"
id="rect3350"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssscccssssssssssssssssssssssssssssssss" /></svg>

Before

Width:  |  Height:  |  Size: 3.1 KiB

15
project.properties Normal file
View File

@ -0,0 +1,15 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system edit
# "ant.properties", and override values to adapt the script to your
# project structure.
#
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target.
target=android-21
android.library.reference.1=../Owncloud-Android-Library

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
res/drawable/login_logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

BIN
res/drawable/next_arrow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
/*
* Copyright (c) 2014-2015, Loic Blot <loic.blot@unix-experience.fr>
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<corners android:radius="6dp" />
<gradient
android:startColor="#66b6df"
android:endColor="#56a6cf"
android:angle="270" />
<padding
android:left="10dp"
android:top="10dp"
android:right="10dp"
android:bottom="10dp" />
</shape>
</item>
</selector>

View File

@ -0,0 +1,122 @@
<!--
/*
* Copyright (c) 2014-2015, Loic Blot <loic.blot@unix-experience.fr>
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="fr.unix_experience.owncloud_sms.activities.LoginActivity" >
<!-- Login progress -->
<ProgressBar
android:id="@+id/login_progress"
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:visibility="gone" />
<ScrollView
android:id="@+id/login_form"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:id="@+id/email_login_form"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<ImageView
android:id="@+id/ocsms_logo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="@drawable/login_logo"
android:contentDescription="@string/login_logo" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Spinner
android:id="@+id/oc_protocol"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:entries="@array/protocol_array">
</Spinner>
<EditText
android:id="@+id/oc_server"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="@string/prompt_serverURI"
android:inputType="textUri" >
<requestFocus />
</EditText>
</LinearLayout>
<AutoCompleteTextView
android:id="@+id/oc_login"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/prompt_login"
android:inputType="textEmailAddress"
android:maxLines="1"
android:singleLine="true" />
<EditText
android:id="@+id/oc_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/prompt_password"
android:imeActionId="@+id/oc_login"
android:imeActionLabel="@string/action_sign_in_short"
android:imeOptions="actionUnspecified"
android:inputType="textPassword"
android:maxLines="1"
android:singleLine="true" />
<Button
android:id="@+id/oc_signin_button"
style="?android:textAppearanceSmall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/action_sign_in_short"
android:textStyle="bold" />
</LinearLayout>
</ScrollView>
</LinearLayout>

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
* Copyright (c) 2014, Loic Blot <loic.blot@unix-experience.fr>
/*
* Copyright (c) 2014-2015, Loic Blot <loic.blot@unix-experience.fr>
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -25,9 +24,10 @@
* SUCH DAMAGE.
*/
-->
<resources
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="MissingTranslation">
<!-- Translations must begin here -->
<string name="gp_short_description">SMS de Nextcloud sincroniza tu SMS local con tu instancia Nextcloud</string>
</resources>
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="fr.unix_experience.owncloud_sms.activities.MainActivity" />

View File

@ -1,4 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
* Copyright (c) 2014-2015, Loic Blot <loic.blot@unix-experience.fr>
@ -25,8 +24,8 @@
* SUCH DAMAGE.
*/
-->
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
@ -34,73 +33,61 @@
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="fr.unix_experience.owncloud_sms.activities.remote_account.RestoreMessagesActivity">
<ProgressBar
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/progressbar_restore"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"/>
tools:context="fr.unix_experience.owncloud_sms.MainActivity$PlaceholderFragment" >
<TextView
android:text="@string/error_make_default_sms_app"
android:id="@+id/main_tv_accounts"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="41dp"
android:id="@+id/tv_error_default_smsapp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:textColor="@color/holo_red_light"
android:textAlignment="center"/>
android:text="@string/ma_title_add_account"
android:textAppearance="?android:attr/textAppearanceLarge" />
<Button
android:text="@string/fix_permissions"
android:id="@+id/mail_button_accounts"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_error_default_smsapp"
android:layout_below="@+id/main_tv_accounts"
android:layout_centerHorizontal="true"
android:layout_marginTop="32dp"
android:id="@+id/button_fix_permissions"
style="@style/Widget.AppCompat.Button"/>
android:layout_marginTop="26dp"
android:onClick="openAddAccount"
android:background="@drawable/standard_button"
style="@style/StandardButton"
android:text="@string/ma_button_goto_sync" />
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/main_tv_accounts"
android:layout_alignStart="@+id/main_tv_accounts"
android:layout_below="@+id/mail_button_accounts"
android:layout_marginTop="18dp"
android:text="@string/ma_title_change_settings"
android:textAppearance="?android:attr/textAppearanceLarge" />
<Button
android:text="@string/launch_restore"
android:id="@+id/main_button_settings"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button_launch_restore"
style="@style/Widget.AppCompat.Button.Colored"
android:textSize="24sp"
android:textAllCaps="false"
android:paddingStart="25dp"
android:paddingEnd="25dp"
android:paddingBottom="15dp"
android:paddingTop="15dp"
android:fontFamily="sans-serif-medium"
android:layout_alignBaseline="@+id/button_fix_permissions"
android:layout_alignBottom="@+id/button_fix_permissions"
android:layout_centerHorizontal="true"/>
<TextView
android:text="@string/restore_finished"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_below="@+id/textView1"
android:layout_centerHorizontal="true"
android:id="@+id/tv_restore_finished"
android:textSize="24sp"
android:textAlignment="center"
android:textColor="@android:color/holo_green_dark"
android:textAllCaps="false"
android:visibility="invisible"/>
android:layout_marginTop="19dp"
android:onClick="openAppSettings"
android:background="@drawable/standard_button"
style="@style/StandardButton"
android:text="@string/ma_button_goto_settings" />
<TextView
<ImageView
android:id="@+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/progressbar_restore"
android:layout_centerHorizontal="true"
android:id="@+id/tv_progress_value"
android:text="@string/x_messages_restored"/>
android:layout_alignLeft="@+id/textView1"
android:layout_alignStart="@+id/textView1"
android:layout_below="@+id/main_button_settings"
android:layout_marginTop="33dp"
android:src="@drawable/next_arrow" />
</RelativeLayout>
</RelativeLayout>

View File

@ -0,0 +1,73 @@
<!--
/*
* Copyright (c) 2014-2015, Loic Blot <loic.blot@unix-experience.fr>
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="fr.unix_experience.owncloud_sms.MainActivity$PlaceholderFragment" >
<TextView
android:id="@+id/section_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/main_title_welcome"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:text="@string/ma_title_welcome"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="@+id/main_tv_welcome"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/section_label"
android:layout_alignStart="@+id/section_label"
android:layout_below="@+id/section_label"
android:layout_marginTop="16dp"
android:text="@string/ma_content_welcome"
android:textAppearance="?android:attr/textAppearanceMedium" />
<ImageView
android:id="@+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:maxHeight="@dimen/arrow_max_height"
android:src="@drawable/next_arrow" />
</RelativeLayout>

View File

@ -0,0 +1,93 @@
<!--
/*
* Copyright (c) 2014-2015, Loic Blot <loic.blot@unix-experience.fr>
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="fr.unix_experience.owncloud_sms.MainActivity$PlaceholderFragment" >
<TextView
android:id="@+id/tv_title_thanksto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:text="@string/ma_button_thanksto"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="@+id/tv_thankspeople"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/tv_title_thanksto"
android:layout_marginTop="15dp"
android:text="@string/ma_thanksto_people"
android:textAppearance="?android:attr/textAppearanceMedium" />
<Button
android:id="@+id/button_rateus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_rateUs"
android:layout_centerHorizontal="true"
android:layout_marginTop="15dp"
android:minHeight="36dp"
android:text="@string/ma_button_rate_us"
android:onClick="openGooglePlayStore"
android:background="@drawable/standard_button"
style="@style/StandardButton"
android:textAlignment="center" />
<TextView
android:id="@+id/ma_title_rateus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/tv_thankspeople"
android:layout_alignStart="@+id/tv_rateUs"
android:layout_below="@+id/tv_thankspeople"
android:layout_marginTop="25dp"
android:text="@string/ma_title_rate_us"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="@+id/tv_rateUs"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:layout_below="@+id/ma_title_rateus"
android:text="@string/ma_content_rate_us"
android:textAppearance="?android:attr/textAppearanceMedium" />
</RelativeLayout>

View File

@ -25,19 +25,17 @@
* SUCH DAMAGE.
*/
-->
<resources
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="MissingTranslation">
<resources>
<!-- Translation version, reference for translators -->
<string name="gp_translation_version">3</string>
<string name="translation_version">3</string>
<!-- Translations must begin here -->
<string name="gp_short_description">Nextcloud SMS synchronizuje vaše lokální SMS zprávy na váš server Nextcloud</string>
<string name="gp_short_description">ownCloud SMS synchronizuje vaše lokální SMS zprávy na váš server ownCloud</string>
<string name="gp_description">
Aplikace ownCloud SMS synchronizuje vaše SMS zprávy na vzdálenou instanci ownCloud, kde si poté můžete zprávy přečíst.
Zasílání SMS ze serveru ownCloud bude doplněno v příštích vydáních.
Applikace je plně kompatibilní pro Android 4.0 až 6.0
Applikace je plně kompatibilní pro Android 4.0 až 5.0
</string>
</resources>
</resources>

148
res/values-cs/strings.xml Normal file
View File

@ -0,0 +1,148 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
* Copyright (c) 2014-2015, Loic Blot <loic.blot@unix-experience.fr>
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-->
<resources>
<!-- Translation version, reference for translators -->
<string name="translation_version">5</string>
<!-- Translations must begin there -->
<!-- Preferences -->
<string name="pref_title_sync">SMS - rychle</string>
<string name="pref_title_sync_frequency">Frekvence rychlé synchronizace</string>
<string name="pref_title_slow_sync">SMS - pomalu a bezpečně</string>
<string name="pref_title_slow_sync_frequency">Frekvence bezpečné pomalé synchronizace</string>
<string name="action_settings">Nastavení</string>
<string name="sync_now">Synchronizovat teď</string>
<string name="pref_category_sync">Synchronizace</string>
<string name="title_global_pref_to_general_prefs">Všeobecné možnosti</string>
<string name="summary_global_pref_to_general_prefs">Možnosti synchronizace</string>
<string name="summary_notif_prefs">Upozornění</string>
<string name="pref_header_data_sync">Data a synchronizace</string>
<string name="title_activity_general_settings">Hlavní nastavení</string>
<string-array name="pref_sync_frequency_titles">
<item>5 minut</item>
<item>15 minut</item>
<item>30 minut</item>
<item>1 hodina</item>
<item>3 hodiny</item>
<item>6 hodin</item>
<item>12 hodin</item>
<item>24 hodin</item>
<item>Nikdy</item>
</string-array>
<string-array name="pref_sync_frequency_values">
<item>5</item>
<item>15</item>
<item>30</item>
<item>60</item>
<item>180</item>
<item>360</item>
<item>720</item>
<item>1440</item>
<item>-1</item>
</string-array>
<string-array name="pref_slow_sync_frequency_titles">
<item>1 hodina</item>
<item>3 hodiny</item>
<item>6 hodin</item>
<item>12 hodin</item>
<item>24 hodin</item>
<item>Nikdy</item>
</string-array>
<string-array name="pref_slow_sync_frequency_values">
<item>60</item>
<item>180</item>
<item>360</item>
<item>720</item>
<item>1440</item>
<item>-1</item>
</string-array>
<string name="title_activity_login">Přihlášení</string>
<!-- Login -->
<string name="prompt_login">Login</string>
<string name="prompt_password">Heslo</string>
<string name="action_sign_in">Přihlásit se nebo registrovat</string>
<string name="action_sign_in_short">Přihlášení</string>
<string name="error_invalid_login">Nesprávné jméno nebo heslo</string>
<string name="error_invalid_password">Toto heslo je příliš krátké</string>
<string name="error_field_required">Toto pole je vyžadováno</string>
<string name="prompt_serverURI">Adresa serveru</string>
<string name="error_invalid_server_address">Neplatná adresa serveru</string>
<string name="error_connection_failed">Připojení selhalo, ujistěte se, že máte správný server</string>
<string name="error_http_connection_failed">Nelze provést připojení přes HTTP. Ujistěte se, že je webový server dostupný</string>
<string-array name="protocol_array">
<item>https://</item>
<item>http://</item>
</string-array>
<!-- Main activity -->
<string name="ma_button_rate_us">Ohodnoťit!</string>
<string name="ma_button_thanksto">Poděkování</string>
<string name="ma_title_rate_us">Ohodnoťit!</string>
<string name="ma_content_rate_us">Pokud se vám tato aplikace líbí, ohodnoťte ji v Obchodě Google Play</string>
<string name="ma_title_add_account">Přidat účet</string>
<string name="ma_button_goto_sync">Přejít na Účty a synchronizaci</string>
<string name="ma_title_change_settings">Změnit nastavení aplikace</string>
<string name="ma_button_goto_settings">Přejít do Nastavení</string>
<string name="ma_title_welcome">Vítejte</string>
<string name="ma_content_welcome">Vítejte v aplikaci ownCloud SMS. Tato aplikace umožnuje sychronizovat SMS do vašeho účtu na serveru ownCloud za pomoci aplikace pro SMS.</string>
<string name="ma_thanksto_people">ownCloud vývojáři\n\ přispěvatelé a ti co hlásí chyby</string>
<!-- Notifications -->
<string name="sync_title">Proces synchronizace</string>
<string name="sync_inprogress">Probíhá synchronizace...</string>
<string name="fatal_error">Chyba !</string>
<!-- Errors -->
<string name="err_sync_get_smslist">Chyba #1: Přijata neplatná data ze serveru při přijímání předchozích zpráv</string>
<string name="err_sync_craft_http_request">Chyba #2: Chyba při vytváření HTTP požadavku</string>
<string name="err_sync_push_request">Chyba #3: Požadavek Push selhal</string>
<string name="err_sync_push_request_resp">Chyba #4: Přijata neplatná data ze serveru při jejich odesílání</string>
<string name="err_sync_create_json_null_smslist">Chyba #5: NULL SMS List</string>
<string name="err_sync_create_json_put_smslist">Chyba #6: Chyba při vytváření Push požadavku</string>
<string name="err_sync_create_json_request_encoding">Chyba #7: Nepodporované kódování při vytváření požadavku</string>
<string name="err_sync_auth_failed">Chyba #8: Ověření selhalo</string>
<string name="err_sync_http_request_returncode_unhandled">Chyba #9: Server nastavil neznámý HTTP kód odpovědi</string>
<string name="err_sync_http_request_connect">Chyba #11: Nelze se připojit k ownCloud serveru</string>
<string name="err_sync_http_request_httpexception">Chyba #12: Nelze se připojit k ownCloud serveru</string>
<string name="err_sync_http_request_ioexception">Chyba #13: Nelze se připojit k ownCloud serveru</string>
<string name="err_sync_http_request_resp">Chyba #14: Nelze zpracovat odpověď serveru</string>
<string name="err_sync_http_request_parse_resp">Chyba #15: Nelze zpracovat odpověď serveru</string>
<string name="err_sync_no_connection_available">Chyba #16: Není dostupné datové připojení</string>
<string name="err_sync_account_unparsable">Chyba #17: účet poškozený Znovu nakonfigurovat</string>
<string name="title_activity_main">MainActivity</string>
<string name="title_section1">Sekce 1</string>
<string name="title_section2">Sekce 2</string>
<string name="title_section3">Sekce 3</string>
<string name="title_activity_main_activity2">MainActivity2</string>
</resources>

View File

@ -25,16 +25,18 @@
* SUCH DAMAGE.
*/
-->
<resources
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="MissingTranslation">
<!-- Translations must begin here -->
<string name="gp_short_description">A Nextcloud SMS szinkronizálja a helyi SMS-eit a Nextcloud példányával</string>
<resources>
<!-- Translation version, reference for translators -->
<string name="translation_version">3</string>
<!-- Translations must begin there -->
<string name="gp_short_description">Mit ownCloud SMS kannst Du Deine SMS mit Deiner ownCloud synchronisieren</string>
<string name="gp_description">
A Nextcloud SMS szolgáltatás szinkronizálja az SMS üzeneteit egy távoli Nextcloud példánnyal, és onnan kiolvashatja azokat.
Die ownCloud SMS App synchronisiert Deine SMS-Nachrichten mit einer ownCloud-Instanz und erlaubt Dir, die SMS dort zu lesen.
A távoli Nextcloud rendszerre történő SMS küldés egy későbbi verzióban lesz elérhető funkció.
In kommenden Versionen soll auch den SMS-Versand von der ownCloud-Instanz aus möglich sein.
Auf diese Weise wirst Du von überall in der Welt SMS versenden können, solange Dein Android-Smartphone GSM- und Datenempfang hat.
Ez a szolgáltatás teljesen kompatibilis az Android 4.0 és 6.0 közti rendszerekkel.
Die App ist vollständig kompatibel mit Android 4.0 bis 5.0
</string>
</resources>

133
res/values-de/strings.xml Normal file
View File

@ -0,0 +1,133 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
* Copyright (c) 2014, Loic Blot <loic.blot@unix-experience.fr>
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-->
<resources>
<!-- Translation version, reference for translators -->
<string name="translation_version">2</string>
<!-- Translations must begin there -->
<!-- Preferences -->
<string name="pref_title_sync">SMS - Schnell</string>
<string name="pref_title_sync_frequency">Schnelle Sync-Frequenz</string>
<string name="pref_title_slow_sync">SMS - Langsam &amp; Sicher</string>
<string name="pref_title_slow_sync_frequency">Langsame Sync-Frequenz</string>
<string name="action_settings">Einstellungen</string>
<string name="sync_now">Jetzt synchronisieren</string>
<string name="pref_category_sync">Synchronisierung</string>
<string name="title_global_pref_to_general_prefs">Allg. Einstellungen</string>
<string name="summary_global_pref_to_general_prefs">Sync-Einstellungen</string>
<string name="summary_notif_prefs">Benachrichtigungen</string>
<string name="pref_header_data_sync">Daten &amp; Sync</string>
<string name="title_activity_general_settings">Allg. Einstellungen</string>
<string-array name="pref_sync_frequency_titles">
<item>5 Minuten</item>
<item>15 Minuten</item>
<item>30 Minuten</item>
<item>1 Stunde</item>
<item>3 Stunden</item>
<item>6 Stunden</item>
<item>12 Stunden</item>
<item>24 Stunden</item>
<item>Nie</item>
</string-array>
<string-array name="pref_sync_frequency_values">
<item>5</item>
<item>15</item>
<item>30</item>
<item>60</item>
<item>180</item>
<item>360</item>
<item>720</item>
<item>1440</item>
<item>-1</item>
</string-array>
<string-array name="pref_slow_sync_frequency_titles">
<item>1 Stunde</item>
<item>3 Stunden</item>
<item>6 Stunden</item>
<item>12 Stunden</item>
<item>24 Stunden</item>
<item>Nie</item>
</string-array>
<string-array name="pref_slow_sync_frequency_values">
<item>60</item>
<item>180</item>
<item>360</item>
<item>720</item>
<item>1440</item>
<item>-1</item>
</string-array>
<string name="title_activity_login">Einloggen</string>
<!-- Login -->
<string name="prompt_login">Login</string>
<string name="prompt_password">Passwort</string>
<string name="action_sign_in">Einloggen oder Registrieren</string>
<string name="action_sign_in_short">Einloggen</string>
<string name="error_invalid_login">Falscher Benutzername oder Passwort</string>
<string name="error_invalid_password">Dieses Passwort ist zu kurz</string>
<string name="error_field_required">Pflichtfeld</string>
<string name="prompt_serverURI">Server-Adresse</string>
<string name="error_invalid_server_address">Ungültige Serveradresse</string>
<string name="error_connection_failed">Verbindung fehlgeschlagen, ist dies der richtige Server?</string>
<string name="error_http_connection_failed">Kann keine HTTP-Verbindung aufbauen. Läuft der Webserver unter dieser Adresse?</string>
<string-array name="protocol_array">
<item>https://</item>
<item>http://</item>
</string-array>
<!-- Notifications -->
<string name="sync_title">Synchronisation</string>
<string name="sync_inprogress">Sychronisation läuft...</string>
<string name="fatal_error">Kritischer Fehler!</string>
<!-- Errors -->
<string name="err_sync_get_smslist">Fehler #1: Bei vorherigen Nachrichten ungültige Serverdaten empfangen</string>
<string name="err_sync_craft_http_request">Fehler #2: Fehler bei der Erstellung des HTTP-Requests</string>
<string name="err_sync_push_request">Fehler #3: Push-Request fehlgeschlagen</string>
<string name="err_sync_push_request_resp">Fehler #4: Beim Pushen von Daten ungültige Serverdaten empfangen</string>
<string name="err_sync_create_json_null_smslist">Fehler #5: SMS-Liste gab NULL zurück</string>
<string name="err_sync_create_json_put_smslist">Fehler #6: Fehler bei der Erstellung des Push-Requests</string>
<string name="err_sync_create_json_request_encoding">Fehler #7: Ungültige Zeichenkodierung bei der Erstellung des Requests</string>
<string name="err_sync_auth_failed">Fehler #8: Anmeldung fehlgeschlagen</string>
<string name="err_sync_http_request_returncode_unhandled">Fehler #9: Unbekannter HTTP-Antwortcode vom Server</string>
<string name="err_sync_http_request_connect">Fehler #11: Konnte nicht mit der ownCloud-Instanz verbinden (HTTP-Request)</string>
<string name="err_sync_http_request_httpexception">Fehler #12: Konnte nicht mit der ownCloud-Instanz verbinden (HTTP-Ausnahme)</string>
<string name="err_sync_http_request_ioexception">Fehler #13: Konnte nicht mit der ownCloud-Instanz verbinden (IO-Fehler)</string>
<string name="err_sync_http_request_resp">Fehler #14: Konnte Server-Antwort nicht parsen</string>
<string name="err_sync_http_request_parse_resp">Fehler #15: Konnte Server-Antwort nicht parsen</string>
</resources>

View File

@ -27,15 +27,15 @@
-->
<resources>
<!-- Translation version, reference for translators -->
<string name="gp_translation_version">3</string>
<string name="translation_version">3</string>
<!-- Translations must begin here -->
<string name="gp_short_description">Nextcloud SMS synchronize your local SMS on your Nextcloud instance</string>
<string name="gp_short_description">ownCloud SMS synchronize your local SMS on your ownCloud instance</string>
<string name="gp_description">
ownCloud SMS application synchronize your SMS messages on a remote ownCloud instance and let you read your messages from it.
Sending SMS from ownCloud instance will coming in a future release.
Application is fully compatible from Android 4.0 to 6.0
Application is fully compatible from Android 4.0 to 5.0
</string>
</resources>

151
res/values-en/strings.xml Normal file
View File

@ -0,0 +1,151 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
* Copyright (c) 2014, Loic Blot <loic.blot@unix-experience.fr>
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-->
<resources>
<!-- Translation version, reference for translators -->
<string name="translation_version">5</string>
<!-- Translations must begin there -->
<!-- Preferences -->
<string name="pref_title_sync">Fast Sync</string>
<string name="pref_title_sync_frequency">Fast Sync frequency</string>
<string name="pref_title_slow_sync">Secure Slow Sync</string>
<string name="pref_title_slow_sync_frequency">Secure Slow Sync frequency</string>
<string name="action_settings">Settings</string>
<string name="sync_now">Synchronize now</string>
<string name="pref_category_sync">Synchronization</string>
<string name="title_global_pref_to_general_prefs">General preferences</string>
<string name="summary_global_pref_to_general_prefs">Sync options</string>
<string name="summary_notif_prefs">Notifications</string>
<string name="pref_header_data_sync">Data &amp; sync</string>
<string name="title_activity_general_settings">General Settings</string>
<string-array name="pref_sync_frequency_titles">
<item>5 minutes</item>
<item>15 minutes</item>
<item>30 minutes</item>
<item>1 hour</item>
<item>3 hours</item>
<item>6 hours</item>
<item>12 hours</item>
<item>24 hours</item>
<item>Never</item>
</string-array>
<string-array name="pref_sync_frequency_values">
<item>5</item>
<item>15</item>
<item>30</item>
<item>60</item>
<item>180</item>
<item>360</item>
<item>720</item>
<item>1440</item>
<item>-1</item>
</string-array>
<string-array name="pref_slow_sync_frequency_titles">
<item>1 minute</item>
<item>1 hour</item>
<item>3 hours</item>
<item>6 hours</item>
<item>12 hours</item>
<item>24 hours</item>
<item>Never</item>
</string-array>
<string-array name="pref_slow_sync_frequency_values">
<item>1</item>
<item>60</item>
<item>180</item>
<item>360</item>
<item>720</item>
<item>1440</item>
<item>-1</item>
</string-array>
<string name="title_activity_login">Sign in</string>
<!-- Login -->
<string name="prompt_login">Login</string>
<string name="prompt_password">Password </string>
<string name="action_sign_in">Sign in or register</string>
<string name="action_sign_in_short">Sign in</string>
<string name="error_invalid_login">Login or password incorrect</string>
<string name="error_invalid_password">This password is too short</string>
<string name="error_field_required">This field is required</string>
<string name="prompt_serverURI">Server address</string>
<string name="error_invalid_server_address">Invalid server address</string>
<string name="error_connection_failed">Connection failed, ensure this is the right server</string>
<string name="error_http_connection_failed">Unable to perform a HTTP connection. Please ensure there is a web server</string>
<string-array name="protocol_array">
<item>https://</item>
<item>http://</item>
</string-array>
<!-- Main activity -->
<string name="ma_button_rate_us">Rate us !</string>
<string name="ma_button_thanksto">Thanks to</string>
<string name="ma_title_rate_us">Rate us !</string>
<string name="ma_content_rate_us">If you like this application, please give rate us on Google Play Store</string>
<string name="ma_title_add_account">Add an account</string>
<string name="ma_button_goto_sync">Go to Accounts and Sync</string>
<string name="ma_title_change_settings">Change app settings</string>
<string name="ma_button_goto_settings">Go to Settings</string>
<string name="ma_title_welcome">Welcome</string>
<string name="ma_content_welcome">Welcome to ownCloud SMS application. This application let you synchronize your SMS to your ownCloud instance using SMS app.</string>
<string name="ma_thanksto_people">ownCloud developers\n\
Contributors and issue\'s reporters</string>
<!-- Notifications -->
<string name="sync_title">Sync process</string>
<string name="sync_inprogress">Sync in progress...</string>
<string name="fatal_error">Fatal error ! </string>
<!-- Errors -->
<string name="err_sync_get_smslist">Error #1: Invalid data received from server when getting previous messages</string>
<string name="err_sync_craft_http_request">Error #2: Error while crafting HTTP request</string>
<string name="err_sync_push_request">Error #3: Push request failed</string>
<string name="err_sync_push_request_resp">Error #4: Invalid datas received from server when pushing datas</string>
<string name="err_sync_create_json_null_smslist">Error #5: NULL Sms List</string>
<string name="err_sync_create_json_put_smslist">Error #6: Error while crafting push request</string>
<string name="err_sync_create_json_request_encoding">Error #7: Unsupported encoding when generating request</string>
<string name="err_sync_auth_failed">Error #8: Authentication failed</string>
<string name="err_sync_http_request_returncode_unhandled">Error #9: Server set unhandled HTTP return code</string>
<string name="err_sync_http_request_connect">Error #11: Unable to perform a connection to ownCloud instance</string>
<string name="err_sync_http_request_httpexception">Error #12: Unable to perform a connection to ownCloud instance</string>
<string name="err_sync_http_request_ioexception">Error #13: Unable to perform a connection to ownCloud instance</string>
<string name="err_sync_http_request_resp">Error #14: Unable to parse server response</string>
<string name="err_sync_http_request_parse_resp">Error #15: Unable to parse server response</string>
<string name="err_sync_no_connection_available">Error #16: No data connection available</string>
<string name="err_sync_account_unparsable">Error #17: malformed account. Please reconfigure it</string>
</resources>

View File

@ -25,16 +25,15 @@
* SUCH DAMAGE.
*/
-->
<resources
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="MissingTranslation">
<!-- Translations must begin here -->
<string name="gp_short_description">Nextcloud SMS synkroniserer dine lokale SMS med din Nextcloud server</string>
<string name="gp_description">
Nextcloud SMS app synkroniserer dine SMS beskeder med en Nextcloud server og lader dig læse dem der.
<resources>
<!-- Translation version, reference for translators -->
<string name="translation_version">0</string>
<string name="gp_short_description">ownCloud SMS sincroniza sus mensajes SMS locales en su servidor ownCloud</string>
<string name="gp_description">
La aplicación ownCloud SMS sincroniza sus mensajes SMS en un servidor ownCloud remoto y le permite leer sus mensajes desde él.
Afsendelse af SMS fra Nextcloud serveren kommer i en senere udgivelse.
El envio de SMS desde el servidor ownCloud será implementado en futuras versiones.
App\'en er fuldt kompatibel med Android 4.0 til 6.0
</string>
La aplicación es totalmente compatible con Android 4.0 a 5.0
</string>
</resources>

94
res/values-es/strings.xml Normal file
View File

@ -0,0 +1,94 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
* Copyright (c) 2014, Loic Blot <loic.blot@unix-experience.fr>
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-->
<resources>
<!-- Translation version, reference for translators -->
<string name="translation_version">1</string>
<!-- Translations must begin there -->
<!-- Preferences -->
<string name="pref_title_sync_frequency">Frecuencia de sincronización</string>
<string name="action_settings">Configuración</string>
<string name="sync_now">Sincronizar ahora</string>
<string name="pref_category_sync">Sincronización</string>
<string name="title_global_pref_to_general_prefs">Preferencias generales</string>
<string name="summary_global_pref_to_general_prefs">Opciones de sincronización</string>
<string name="summary_notif_prefs">Notificaciones</string>
<string name="pref_header_data_sync">Sincronizar &amp; datos</string>
<string name="title_activity_general_settings">Configuración general</string>
<string-array name="pref_sync_frequency_titles">
<item>15 minutos</item>
<item>30 minutos</item>
<item>1 hora</item>
<item>3 horas</item>
<item>6 horas</item>
<item>12 horas</item>
<item>24 horas</item>
<item>Nunca</item>
</string-array>
<string-array name="pref_sync_frequency_values">
<item>15</item>
<item>30</item>
<item>60</item>
<item>180</item>
<item>360</item>
<item>720</item>
<item>1440</item>
<item>-1</item>
</string-array>
<string name="title_activity_login">Unirse</string>
<!-- Login -->
<string name="prompt_login">Usuario</string>
<string name="prompt_password">Contraseña</string>
<string name="action_sign_in">Unirse o registrarse</string>
<string name="action_sign_in_short">Unirse</string>
<string name="error_invalid_login">Usuario o contraseña incorrecto</string>
<string name="error_invalid_password">Contraseña demasiado corta</string>
<string name="error_field_required">Campo requerido</string>
<string name="prompt_serverURI">Dirección del servidor</string>
<string name="error_invalid_server_address">Dirección inválida</string>
<string name="error_connection_failed">Imposible conectar al servidor. Por favor asegúrese que la dirección del servidor es correcta</string>
<string name="error_http_connection_failed">Imposible establecer una conexión HTTP. Por favor asegúrese que el servidor HTTP esta ejecutándose</string>
<string-array name="protocol_array">
<item>https://</item>
<item>http://</item>
</string-array>
<!-- Notifications -->
<string name="sync_title">Proceso de sincronización</string>
<string name="sync_inprogress">Sincronización en progreso...</string>
<string name="fatal_error">Error Fatal ! </string>
</resources>

View File

@ -25,16 +25,17 @@
* SUCH DAMAGE.
*/
-->
<resources
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="MissingTranslation">
<!-- Translations must begin here -->
<string name="gp_short_description">Nextcloud SMS sincroniza los SMS na to instancia de Nextcloud</string>
<resources>
<!-- Translation version, reference for translators -->
<string name="translation_version">3</string>
<!-- Translations must begin there -->
<string name="gp_short_description">ownCloud SMS permet de synchroniser vos SMS sur votre instance ownCloud</string>
<string name="gp_description">
L\'aplicación Nextcloud SMS sincroniza los SMS nuna insntacia remota de Nextcloud y déxate lleer los mensaxes dende ellí.
L\'application ownCloud SMS vous permet de synchroniser vos messages SMS sur une instance ownCloud distante et ainsi de pouvoir les lire.
Nuna versión futura, va poder unviase SMS dende Nextcloud..
Il est prévu d\'ajouter le support de l\'envoi de SMS depuis l\'instance ownCloud dans une future mise à jour, vous permettant d\'envoyer des SMS depuis n\'importe où dans le monde, en laissant votre téléphone Android à portée d\'un accès DATA et GSM
L\'aplicación ye completamente compatible coles d\'Android 4.0 n\'adelantre
L\'application est pleinement compatible des versions Android 4.0 à 5.0
</string>
</resources>
</resources>

110
res/values-fr/strings.xml Normal file
View File

@ -0,0 +1,110 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
* Copyright (c) 2014, Loic Blot <loic.blot@unix-experience.fr>
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-->
<resources>
<!-- Translation version, reference for translators -->
<string name="translation_version">3</string>
<!-- Translations must begin there -->
<string name="app_name">ownCloud-SMS</string>
<string name="action_settings">Paramètres</string>
<string name="sync_now">Synchroniser maintenant</string>
<!-- Preferences -->
<string name="pref_category_sync">Synchronisation</string>
<string name="title_global_pref_to_general_prefs">Préférences générales</string>
<string name="summary_global_pref_to_general_prefs">Options de synchronisation</string>
<string name="summary_notif_prefs">Notifications</string>
<string name="pref_header_data_sync">Données &amp; synchronisation</string>
<string name="pref_title_sync_frequency">Fréquence de synchronisation</string>
<string name="pref_title_sync">SMS - Méthode rapide</string>
<string name="pref_title_slow_sync">SMS - Méthode lente (sécurisée)</string>
<string name="pref_title_slow_sync_frequency">Fréquence de la synchronisation lente</string>
<string name="title_activity_general_settings">Préférences générales</string>
<string-array name="pref_sync_frequency_titles">
<item>15 minutes</item>
<item>30 minutes</item>
<item>1 heure</item>
<item>3 heures</item>
<item>6 heures</item>
<item>12 heures</item>
<item>24 heures</item>
<item>Jamais</item>
</string-array>
<string-array name="pref_sync_frequency_values">
<item>15</item>
<item>30</item>
<item>60</item>
<item>180</item>
<item>360</item>
<item>720</item>
<item>1440</item>
<item>-1</item>
</string-array>
<string name="title_activity_login">Connexion</string>
<!-- Login -->
<string name="prompt_login">Identifiant</string>
<string name="prompt_password">Mot de passe </string>
<string name="action_sign_in">S\'enregistrer ou se connecter</string>
<string name="action_sign_in_short">Se connecter</string>
<string name="error_invalid_login">Identifiant ou mot de passe incorrect</string>
<string name="error_invalid_password">Ce mot de passe est trop court</string>
<string name="error_field_required">Ce champ est requis</string>
<string name="prompt_serverURI">Adresse du serveur</string>
<string name="error_invalid_server_address">Adresse invalide</string>
<string name="error_connection_failed">Echec de connexion, assurer vous qu\'il s\'agit du bon serveur</string>
<string name="error_http_connection_failed">Impossible d\'effectuer la connexion HTTP. Assurez vous qu\'il s\'agit d\'un serveur HTTP</string>
<!-- Main activity -->
<string name="ma_button_rate_us">Notez nous !</string>
<string name="ma_button_thanksto">Remerciements</string>
<string name="ma_title_rate_us">Notez nous !</string>
<string name="ma_content_rate_us">Si vous aimez cette application, n\'hésitez pas à nous noter sur le Google Play Store</string>
<string name="ma_title_add_account">Ajouter un compte</string>
<string name="ma_button_goto_sync">Ouvrir comptes et synchronisation</string>
<string name="ma_title_change_settings">Changer les paramètres de l\'application</string>
<string name="ma_button_goto_settings">Aller dans les paramètres</string>
<string name="ma_title_welcome">Bienvenue</string>
<string name="ma_content_welcome">Bienvenue sur l\'application ownCloud SMS. Cette application va vous permettre de synchroniser vos SMS au sein de votre instance ownCloud en utilisant l\'application dédiée.</string>
<string name="ma_thanksto_people">L\'équipe de développement ownCloud\n\
Les contributeurs et rapporteurs de bugs</string>
<!-- Notifications -->
<string name="sync_title">Processus de synchronisation</string>
<string name="sync_inprogress">Synchonisation en cours...</string>
<string name="fatal_error">Erreur fatale ! </string>
<string name="err_sync_no_connection_available">Erreur #16: Aucune connexion data disponible</string>
<string name="err_sync_account_unparsable">Error #17: Compte mal configuré. Merci de bien vouloir le reconfigurer.</string>
</resources>

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
* Copyright (c) 2014, Loic Blot <loic.blot@unix-experience.fr>
* Copyright (c) 2014-2015, Loic Blot <loic.blot@unix-experience.fr>
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -25,9 +24,16 @@
* SUCH DAMAGE.
*/
-->
<resources
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="MissingTranslation">
<!-- Translations must begin here -->
<string name="gp_short_description">SMS de Nextcloud sincroniza tu SMS local con tu instancia Nextcloud</string>
</resources>
<resources>
<style name="OcSmsTheme" parent="@android:style/Theme.Holo.Light.DarkActionBar">
<item name="android:actionBarStyle">@style/OcSmsActionBar</item>
</style>
<style name="OcSmsActionBar"
parent="@android:style/Widget.Holo.Light.ActionBar.Solid.Inverse">
<item name="android:background">#56a6cf</item>
</style>
</resources>

View File

@ -6,5 +6,5 @@
would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively).
-->
<dimen name="activity_horizontal_margin">64dp</dimen>
<dimen name="nav_drawer_header_height">164dp</dimen>
</resources>

8
res/values/dimens.xml Normal file
View File

@ -0,0 +1,8 @@
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="arrow_max_height">22dp</dimen>
</resources>

View File

@ -25,19 +25,17 @@
* SUCH DAMAGE.
*/
-->
<resources
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="MissingTranslation">
<resources>
<!-- Translation version, reference for translators -->
<string name="gp_translation_version" translatable="false">3</string>
<string name="translation_version">3</string>
<!-- Translations must begin here -->
<string name="gp_short_description">Nextcloud SMS synchronize your local SMS on your Nextcloud instance</string>
<string name="gp_short_description">ownCloud SMS synchronize your local SMS on your ownCloud instance</string>
<string name="gp_description">
Nextcloud SMS application synchronize your SMS messages on a remote Nextcloud instance and let you read your messages from it.
ownCloud SMS application synchronize your SMS messages on a remote ownCloud instance and let you read your messages from it.
Sending SMS from Nextcloud instance will coming in a future release.
Sending SMS from ownCloud instance will coming in a future release.
Application is fully compatible from Android 4.0 to 6.0
Application is fully compatible from Android 4.0 to 5.0
</string>
</resources>
</resources>

161
res/values/strings.xml Normal file
View File

@ -0,0 +1,161 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
* Copyright (c) 2014-2015, Loic Blot <loic.blot@unix-experience.fr>
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-->
<resources>
<!-- Translation version, reference for translators -->
<string name="translation_version">5</string>
<!-- System strings, do not translate -->
<string name="app_name">ownCloud-SMS</string>
<string name="account_type">fr.unix_experience.owncloud_sms</string>
<string name="account_authority">fr.unix_experience.owncloud_sms.datasync.provider</string>
<string name="slowsync_account_authority">fr.unix_experience.owncloud_sms.datasync.slowsync_provider</string>
<string name="target_package">fr.unix_experience.owncloud_sms</string>
<string name="login_logo">Login logo</string>
<!-- System strings: preferences -->
<string name="shared_preference_file">ownCloudSMSPrefs</string>
<string name="pref_lastmsgdate">last_message_date</string>
<!-- Translations must begin there -->
<!-- Preferences -->
<string name="pref_title_sync">SMS - Fast</string>
<string name="pref_title_sync_frequency">Fast Sync frequency</string>
<string name="pref_title_slow_sync">SMS - Slow and Secure</string>
<string name="pref_title_slow_sync_frequency">Secure Slow Sync frequency</string>
<string name="action_settings">Settings</string>
<string name="sync_now">Synchronize now</string>
<string name="pref_category_sync">Synchronization</string>
<string name="title_global_pref_to_general_prefs">General preferences</string>
<string name="summary_global_pref_to_general_prefs">Sync options</string>
<string name="summary_notif_prefs">Notifications</string>
<string name="pref_header_data_sync">Data &amp; sync</string>
<string name="title_activity_general_settings">General Settings</string>
<string-array name="pref_sync_frequency_titles">
<item>5 minutes</item>
<item>15 minutes</item>
<item>30 minutes</item>
<item>1 hour</item>
<item>3 hours</item>
<item>6 hours</item>
<item>12 hours</item>
<item>24 hours</item>
<item>Never</item>
</string-array>
<string-array name="pref_sync_frequency_values">
<item>5</item>
<item>15</item>
<item>30</item>
<item>60</item>
<item>180</item>
<item>360</item>
<item>720</item>
<item>1440</item>
<item>-1</item>
</string-array>
<string-array name="pref_slow_sync_frequency_titles">
<item>1 hour</item>
<item>3 hours</item>
<item>6 hours</item>
<item>12 hours</item>
<item>24 hours</item>
<item>Never</item>
</string-array>
<string-array name="pref_slow_sync_frequency_values">
<item>60</item>
<item>180</item>
<item>360</item>
<item>720</item>
<item>1440</item>
<item>-1</item>
</string-array>
<string name="title_activity_login">Sign in</string>
<!-- Login -->
<string name="prompt_login">Login</string>
<string name="prompt_password">Password </string>
<string name="action_sign_in">Sign in or register</string>
<string name="action_sign_in_short">Sign in</string>
<string name="error_invalid_login">Login or password incorrect</string>
<string name="error_invalid_password">This password is too short</string>
<string name="error_field_required">This field is required</string>
<string name="prompt_serverURI">Server address</string>
<string name="error_invalid_server_address">Invalid server address</string>
<string name="error_connection_failed">Connection failed, ensure this is the right server</string>
<string name="error_http_connection_failed">Unable to perform a HTTP connection. Please ensure there is a web server</string>
<string-array name="protocol_array">
<item>https://</item>
<item>http://</item>
</string-array>
<!-- Main activity -->
<string name="ma_button_rate_us">Rate us !</string>
<string name="ma_button_thanksto">Thanks to</string>
<string name="ma_title_rate_us">Rate us !</string>
<string name="ma_content_rate_us">If you like this application, please give rate us on Google Play Store</string>
<string name="ma_title_add_account">Add an account</string>
<string name="ma_button_goto_sync">Go to Accounts and Sync</string>
<string name="ma_title_change_settings">Change app settings</string>
<string name="ma_button_goto_settings">Go to Settings</string>
<string name="ma_title_welcome">Welcome</string>
<string name="ma_content_welcome">Welcome to ownCloud SMS application. This application let you synchronize your SMS to your ownCloud instance using SMS app.</string>
<string name="ma_thanksto_people">ownCloud developers\n\
Contributors and issue\'s reporters</string>
<!-- Notifications -->
<string name="sync_title">Sync process</string>
<string name="sync_inprogress">Sync in progress...</string>
<string name="fatal_error">Fatal error ! </string>
<!-- Errors -->
<string name="err_sync_get_smslist">Error #1: Invalid data received from server when getting previous messages</string>
<string name="err_sync_craft_http_request">Error #2: Error while crafting HTTP request</string>
<string name="err_sync_push_request">Error #3: Push request failed</string>
<string name="err_sync_push_request_resp">Error #4: Invalid datas received from server when pushing datas</string>
<string name="err_sync_create_json_null_smslist">Error #5: NULL SMS List</string>
<string name="err_sync_create_json_put_smslist">Error #6: Error while crafting push request</string>
<string name="err_sync_create_json_request_encoding">Error #7: Unsupported encoding when generating request</string>
<string name="err_sync_auth_failed">Error #8: Authentication failed</string>
<string name="err_sync_http_request_returncode_unhandled">Error #9: Server set unhandled HTTP return code</string>
<string name="err_sync_http_request_connect">Error #11: Unable to perform a connection to ownCloud instance</string>
<string name="err_sync_http_request_httpexception">Error #12: Unable to perform a connection to ownCloud instance</string>
<string name="err_sync_http_request_ioexception">Error #13: Unable to perform a connection to ownCloud instance</string>
<string name="err_sync_http_request_resp">Error #14: Unable to parse server response</string>
<string name="err_sync_http_request_parse_resp">Error #15: Unable to parse server response</string>
<string name="err_sync_no_connection_available">Error #16: No data connection available</string>
<string name="err_sync_account_unparsable">Error #17: malformed account. Please reconfigure it</string>
<string name="title_activity_main">MainActivity</string>
<string name="title_section1">Section 1</string>
<string name="title_section2">Section 2</string>
<string name="title_section3">Section 3</string>
<string name="title_activity_main_activity2">MainActivity2</string>
</resources>

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
* Copyright (c) 2014, Loic Blot <loic.blot@unix-experience.fr>
* Copyright (c) 2014-2015, Loic Blot <loic.blot@unix-experience.fr>
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -25,9 +24,17 @@
* SUCH DAMAGE.
*/
-->
<resources
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="MissingTranslation">
<!-- Translations must begin here -->
<string name="gp_short_description">Nextcloud SMS sincronice su SMS local con su instancia Nextcloud</string>
</resources>
<resources>
<style name="AppBaseTheme" parent="@android:style/Theme.Holo.Light">
</style>
<!-- Application theme. -->
<style name="AppTheme" parent="AppBaseTheme">
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
</style>
<style name="StandardButton">
<item name="android:textColor">#ffffff</item>
</style>
</resources>

View File

@ -1,6 +1,6 @@
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="@string/account_type"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:smallIcon="@mipmap/ic_launcher"
android:icon="@drawable/ic_launcher"
android:smallIcon="@drawable/ic_launcher"
android:accountPreferences="@xml/global_preferences"/>

View File

@ -0,0 +1,13 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<PreferenceCategory
android:title="@string/summary_global_pref_to_general_prefs">
<ListPreference
android:defaultValue="10"
android:entries="@array/pref_sync_frequency_titles"
android:entryValues="@array/pref_sync_frequency_values"
android:key="sync_frequency"
android:negativeButtonText="@null"
android:positiveButtonText="@null"
android:title="@string/pref_title_sync_frequency" />
</PreferenceCategory>
</PreferenceScreen>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

View File

@ -1 +0,0 @@
include ':ncsmsgo'

View File

@ -0,0 +1,240 @@
package fr.unix_experience.owncloud_sms.activities;
/*
* Copyright (c) 2014-2015, 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 mSlowSyncAccountAuthority;
static String mAccountType;
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
mAccountMgr = AccountManager.get(getBaseContext());
mAccountAuthority = getString(R.string.account_authority);
mSlowSyncAccountAuthority = getString(R.string.slowsync_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"));
//bindPreferenceSummaryToValue(findPreference("slow_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);
}
}
// Slow Sync frequency
} /*else if (prefKey.equals(new String("slow_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], mSlowSyncAccountAuthority);
boolean foundSameSyncCycle = false;
for (int j = 0; j < syncList.size(); j++) {
PeriodicSync ps = syncList.get(i);
if (ps.period == syncFreq && ps.extras.getInt("synctype") == 2) {
foundSameSyncCycle = true;
}
}
if (foundSameSyncCycle == false) {
Bundle b = new Bundle();
b.putInt("synctype", 2);
ContentResolver.removePeriodicSync(myAccountList[i],
mSlowSyncAccountAuthority, b);
ContentResolver.addPeriodicSync(myAccountList[i],
mSlowSyncAccountAuthority, 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"));
//bindPreferenceSummaryToValue(findPreference("slow_sync_frequency"));
}
}
}

View File

@ -22,44 +22,37 @@ 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.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import android.view.KeyEvent;
import android.view.MenuItem;
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.dd.processbutton.iml.ActionProcessButton;
import java.net.MalformedURLException;
import java.net.URL;
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.defines.DefaultPrefs;
import fr.unix_experience.owncloud_sms.engine.OCHttpClient;
import fr.unix_experience.owncloud_sms.exceptions.OCSyncException;
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 AppCompatActivity {
private static final String TAG = LoginActivity.class.getCanonicalName();
public class LoginActivity extends Activity {
/**
* Keep track of the login task to ensure we can cancel it if requested.
*/
@ -70,7 +63,6 @@ public class LoginActivity extends AppCompatActivity {
private EditText _loginView;
private EditText _passwordView;
private EditText _serverView;
private ActionProcessButton _signInButton;
private View mProgressView;
private View mLoginFormView;
@ -79,21 +71,18 @@ public class LoginActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
// Set up the login form.
_protocolView = findViewById(R.id.oc_protocol);
_serverView = findViewById(R.id.oc_server);
_loginView = findViewById(R.id.oc_login);
_protocolView = (Spinner) findViewById(R.id.oc_protocol);
_serverView = (EditText) findViewById(R.id.oc_server);
_loginView = (EditText) findViewById(R.id.oc_login);
_passwordView = findViewById(R.id.oc_password);
_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)) {
KeyEvent keyEvent) {
if (id == R.id.oc_login || id == EditorInfo.IME_NULL) {
attemptLogin();
return true;
}
@ -101,7 +90,7 @@ public class LoginActivity extends AppCompatActivity {
}
});
_signInButton = findViewById(R.id.oc_signin_button);
Button _signInButton = (Button) findViewById(R.id.oc_signin_button);
_signInButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
@ -113,19 +102,6 @@ public class LoginActivity extends AppCompatActivity {
mProgressView = findViewById(R.id.login_progress);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
boolean retval = true;
switch (item.getItemId()) {
case android.R.id.home:
finish();
break;
default:
retval = super.onOptionsItemSelected(item);
}
return retval;
}
/**
* Attempts to sign in or register the account specified by the login form.
* If there are form errors (invalid email, missing fields, etc.), the
@ -148,12 +124,12 @@ public class LoginActivity extends AppCompatActivity {
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));
@ -167,14 +143,14 @@ public class LoginActivity extends AppCompatActivity {
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;
@ -184,23 +160,14 @@ public class LoginActivity extends AppCompatActivity {
if (cancel) {
// There was an error; don't attempt login and focus the first
// form field with an error.
// reset the button progress
_signInButton.setProgress(0);
if (focusView != null) {
focusView.requestFocus();
}
focusView.requestFocus();
} else {
// Show a progress spinner, and kick off a background task to
// perform the user login attempt.
_signInButton.setProgress(25);
showProgress(true);
String serverURL = protocol + serverAddr;
try {
mAuthTask = new UserLoginTask(serverURL, login, password);
mAuthTask.execute((Void) null);
} catch (MalformedURLException e) {
Log.e(TAG, "Invalid server URL " + serverURL);
}
String serverURL = new String(protocol + serverAddr);
mAuthTask = new UserLoginTask(serverURL, login, password);
mAuthTask.execute((Void) null);
}
}
@ -254,118 +221,101 @@ public class LoginActivity extends AppCompatActivity {
* Represents an asynchronous login/registration task used to authenticate
* the user.
*/
public class UserLoginTask extends AsyncTask<Void, Void, Boolean> {
public class UserLoginTask extends AsyncTask<Void, Void, Boolean> {
UserLoginTask(String serverURL, String login, String password) throws MalformedURLException {
_serverURL = new URL(serverURL);
Log.i(TAG, "_serverURL = " + serverURL);
UserLoginTask(String serverURI, String login, String password) {
_serverURI = Uri.parse(serverURI);
_login = login;
_password = password;
_last_http_error = null;
}
@Override
protected Boolean doInBackground(Void... params) {
_returnCode = 0;
OCHttpClient http = new OCHttpClient(getBaseContext(), _serverURL, _login, _password);
try {
Pair<Integer, Integer> vPair = http.getVersion();
_returnCode = vPair.first;
} catch (IllegalArgumentException e) {
Log.w(TAG, "Failed to getVersion, IllegalArgumentException occured: " + e.getMessage());
_returnCode = 597;
} catch (OCSyncException e) {
Log.w(TAG, "Failed to login, OCSyncException occured: " + e.getMessage());
_returnCode = 599;
}
_last_http_error = http.getLastError();
return (_returnCode == 200);
// 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(Boolean success) {
protected void onPostExecute(final Boolean success) {
mAuthTask = null;
showProgress(false);
_signInButton.setProgress(90);
if (success) {
_signInButton.setProgress(100);
String accountType = getIntent().getStringExtra(UserLoginTask.PARAM_AUTHTOKEN_TYPE);
if (accountType == null) {
accountType = getString(R.string.account_type);
}
String accountType = getIntent().getStringExtra(PARAM_AUTHTOKEN_TYPE);
if (accountType == null) {
accountType = getString(R.string.account_type);
}
// Generate a label
String accountLabel = _login + "@" + _serverURL.getHost();
String accountLabel = _login + "@" + _serverURI.getHost();
// We create the account
Account account = new Account(accountLabel, accountType);
final Account account = new Account(accountLabel, accountType);
Bundle accountBundle = new Bundle();
accountBundle.putString("ocLogin", _login);
accountBundle.putString("ocURI", _serverURL.toString());
accountBundle.putString("ocURI", _serverURI.toString());
// And we push it to Android
AccountManager accMgr = AccountManager.get(getApplicationContext());
accMgr.addAccountExplicitly(account, _password, accountBundle);
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, DefaultPrefs.syncInterval * 60);
ContentResolver.addPeriodicSync(account, getString(R.string.account_authority), b, 15 * 60);
// Then it's finished
finish();
// Start sync settings, we have finished to configure account
Intent settingsIntent = new Intent(Settings.ACTION_SYNC_SETTINGS);
settingsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getApplicationContext().startActivity(settingsIntent);
} else {
boolean serverViewRequestFocus = true;
switch (_returnCode) {
case 0:
if (!_last_http_error.isEmpty()) {
_serverView.setError("Low level error: " + _last_http_error);
}
else {
_serverView.setError("Unknown error");
}
break;
case 404:
_serverView.setError(getString(R.string.error_connection_failed_not_found));
break;
case 597:
case INVALID_ADDR:
_serverView.setError(getString(R.string.error_invalid_server_address));
_serverView.requestFocus();
break;
case 400:
case 598:
_serverView.setError(getString(R.string.error_connection_failed));
break;
case 599:
case HTTP_CONN_FAILED:
_serverView.setError(getString(R.string.error_http_connection_failed));
_serverView.requestFocus();
break;
case 401:
case 403:
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();
// Warning, there is no break here to disable serverViewRequestFocus too
case 200:
default:
serverViewRequestFocus = false;
break;
case UNKNOWN_ERROR:
_serverView.setError("UNK");
_serverView.requestFocus();
break;
default:
break;
}
if (serverViewRequestFocus) {
_serverView.requestFocus();
}
// If not ok, reset the progress
if (_returnCode != 200) {
_signInButton.setProgress(0);
}
}
}
@ -374,14 +324,13 @@ public class LoginActivity extends AppCompatActivity {
mAuthTask = null;
showProgress(false);
}
private final URL _serverURL;
private final Uri _serverURI;
private final String _login;
private final String _password;
private String _last_http_error;
private int _returnCode;
static final String PARAM_AUTHTOKEN_TYPE = "auth.token";
private final String TAG = UserLoginTask.class.getCanonicalName();
private LoginReturnCode _returnCode;
public static final String PARAM_AUTHTOKEN_TYPE = "auth.token";
public static final String PARAM_CREATE = "create";
}
}

View File

@ -0,0 +1,166 @@
package fr.unix_experience.owncloud_sms.activities;
/*
* Copyright (c) 2014-2015, Loic Blot <loic.blot@unix-experience.fr>
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
import java.util.List;
import java.util.Vector;
import fr.unix_experience.owncloud_sms.R;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.support.v13.app.FragmentPagerAdapter;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class MainActivity extends Activity {
/**
* The {@link android.support.v4.view.PagerAdapter} that will provide
* fragments for each of the sections. We use a {@link FragmentPagerAdapter}
* derivative, which will keep every loaded fragment in memory. If this
* becomes too memory intensive, it may be best to switch to a
* {@link android.support.v4.app.FragmentStatePagerAdapter}.
*/
PagerAdapter mPagerAdapter;
/**
* The {@link ViewPager} that will host the section contents.
*/
ViewPager mViewPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Create the adapter that will return a fragment for each of the three
// primary sections of the activity.
List<Fragment> fragments = new Vector<Fragment>();
/*
* Add the Main tabs here
*/
fragments.add(Fragment.instantiate(this,StarterFragment.class.getName()));
fragments.add(Fragment.instantiate(this,SecondTestFragment.class.getName()));
fragments.add(Fragment.instantiate(this,ThanksAndRateFragment.class.getName()));
mPagerAdapter = new MainPagerAdapter(getFragmentManager(), fragments);
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mPagerAdapter);
}
/**
* A {@link FragmentPagerAdapter} that returns a fragment corresponding to
* one of the sections/tabs/pages.
*/
public class MainPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragments;
public MainPagerAdapter(FragmentManager fragmentManager, List<Fragment> fragments) {
super(fragmentManager);
mFragments = fragments;
}
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
// Return a PlaceholderFragment (defined as a static inner class
// below).
return mFragments.get(position);
}
@Override
public int getCount() {
// Show 3 total pages.
return mFragments.size();
}
}
/**
* Fragments for activity must be there
*/
public static class StarterFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_mainactivity_main, container,
false);
return rootView;
}
}
public static class SecondTestFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_mainactivity_gotosettings, container,
false);
return rootView;
}
}
public static class ThanksAndRateFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_mainactivity_thanks_note, container,
false);
return rootView;
}
}
public void openAppSettings(View view) {
startActivity(new Intent(this, GeneralSettingsActivity.class));
}
public void openAddAccount(View view) {
startActivity(new Intent(Settings.ACTION_ADD_ACCOUNT));
}
public void openGooglePlayStore(View view) {
Intent intent;
try {
intent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + getPackageName()));
} catch (android.content.ActivityNotFoundException anfe) {
intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + getPackageName()));
}
startActivity(intent);
}
}

View File

@ -17,6 +17,16 @@ package fr.unix_experience.owncloud_sms.authenticators;
* 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;
@ -25,8 +35,7 @@ import android.accounts.NetworkErrorException;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import fr.unix_experience.owncloud_sms.activities.LoginActivity;
import android.util.Log;
public class OwnCloudAuthenticator extends AbstractAccountAuthenticator {
// Simple constructor
@ -47,8 +56,8 @@ public class OwnCloudAuthenticator extends AbstractAccountAuthenticator {
String accountType, String authTokenType,
String[] requiredFeatures, Bundle options)
throws NetworkErrorException {
Bundle result;
Intent intent;
final Bundle result;
final Intent intent;
intent = new Intent(_context, LoginActivity.class);
@ -92,8 +101,96 @@ public class OwnCloudAuthenticator extends AbstractAccountAuthenticator {
// 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);
private final Context _context;
// 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";
}

View File

@ -0,0 +1,65 @@
package fr.unix_experience.owncloud_sms.broadcast_receivers;
/*
* Copyright (c) 2014-2015, 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.engine.ASyncTask;
import fr.unix_experience.owncloud_sms.engine.ConnectivityMonitor;
import fr.unix_experience.owncloud_sms.engine.SmsFetcher;
import fr.unix_experience.owncloud_sms.prefs.OCSMSSharedPrefs;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class ConnectivityChanged extends BroadcastReceiver implements ASyncTask {
@Override
public void onReceive(Context context, Intent intent) {
ConnectivityMonitor cMon = new ConnectivityMonitor(context);
// If data is available and previous dataConnectionState was false, then we need to sync
if (cMon.isValid() && dataConnectionAvailable == false) {
dataConnectionAvailable = true;
Log.d(TAG,"ConnectivityChanged.onReceive, data conn available");
checkMessagesToSent(context);
}
// No data available and previous dataConnectionState was true
else if (dataConnectionAvailable == true && !cMon.isValid()) {
dataConnectionAvailable = false;
Log.d(TAG,"ConnectivityChanges.onReceive: data conn is off");
}
}
private void checkMessagesToSent(Context context) {
// Get last message synced from preferences
Long lastMessageSynced = (new OCSMSSharedPrefs(context)).getLastMessageDate();
Log.d(TAG,"Synced Last:" + lastMessageSynced);
// Now fetch messages since last stored date
JSONArray smsList = new SmsFetcher(context).bufferizeMessagesSinceDate(lastMessageSynced);
if (smsList != null) {
new SyncTask(context, smsList).execute();
}
}
private static boolean dataConnectionAvailable = false;
private static final String TAG = ConnectivityChanged.class.getSimpleName();
}

View File

@ -17,6 +17,7 @@ package fr.unix_experience.owncloud_sms.broadcast_receivers;
* 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;
@ -24,17 +25,15 @@ import android.net.Uri;
import android.os.Handler;
import android.util.Log;
import fr.unix_experience.owncloud_sms.observers.SmsObserver;
public class IncomingSms extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (IncomingSms._mboxObserver == null) {
Log.i(IncomingSms.TAG,"_mboxObserver == null");
IncomingSms._mboxObserver = new SmsObserver(new Handler(), context);
if (_mboxObserver == null) {
Log.d(TAG,"_mboxObserver == null");
_mboxObserver = new SmsObserver(new Handler(), context);
context.getContentResolver().
registerContentObserver(Uri.parse("content://sms"), true, IncomingSms._mboxObserver);
registerContentObserver(Uri.parse("content://sms"), true, _mboxObserver);
}
}

View File

@ -0,0 +1,65 @@
package fr.unix_experience.owncloud_sms.engine;
/*
* Copyright (c) 2014-2015, 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 android.accounts.Account;
import android.accounts.AccountManager;
import android.content.Context;
import android.net.Uri;
import android.os.AsyncTask;
import android.util.Log;
import fr.unix_experience.owncloud_sms.R;
import fr.unix_experience.owncloud_sms.exceptions.OCSyncException;
public interface ASyncTask {
class SyncTask extends AsyncTask<Void, Void, Void>{
public SyncTask(Context context, JSONArray smsList) {
_context = context;
_smsList = smsList;
}
@Override
protected Void doInBackground(Void... params) {
// Get ownCloud SMS account list
AccountManager _accountMgr = AccountManager.get(_context);
Account[] myAccountList = _accountMgr.getAccountsByType(_context.getString(R.string.account_type));
for (int i = 0; i < myAccountList.length; i++) {
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 Context _context;
private JSONArray _smsList;
}
static final String TAG = ASyncTask.class.getSimpleName();
}

View File

@ -0,0 +1,45 @@
package fr.unix_experience.owncloud_sms.engine;
/*
* Copyright (c) 2014-2015, 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
*/
import android.content.Context;
import android.net.ConnectivityManager;
public class ConnectivityMonitor {
public ConnectivityMonitor(Context context) {
_context = context;
}
// Valid connection = WiFi or Mobile data
public boolean isValid() {
if (_cMgr == null) {
_cMgr = (ConnectivityManager) _context.getSystemService(Context.CONNECTIVITY_SERVICE);
}
final android.net.NetworkInfo niWiFi = _cMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
final android.net.NetworkInfo niMobile = _cMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
if (niWiFi.isAvailable() || niMobile.isAvailable()) {
return true;
}
return false;
}
private ConnectivityManager _cMgr;
private Context _context;
}

View File

@ -0,0 +1,386 @@
package fr.unix_experience.owncloud_sms.engine;
/*
* Copyright (c) 2014-2015, 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;
import fr.unix_experience.owncloud_sms.prefs.OCSMSSharedPrefs;
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 2: doPushRequestV2(smsList); break;
case 1:
default: doPushRequestV1(smsList); break;
}
}
public void doPushRequestV1(JSONArray smsList) throws OCSyncException {
// We need to save this date as a step for connectivity change
Long lastMsgDate = (long) 0;
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.fetchAllMessages();
// Get maximum message date present in smsList to keep a step when connectivity changes
lastMsgDate = fetcher.getLastMessageDate();
}
if (smsList.length() == 0) {
Log.d(TAG, "No new SMS to sync, sync done");
return;
}
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);
}
// Push was OK, we can save the lastMessageDate which was saved to server
(new OCSMSSharedPrefs(_context)).setLastMessageDate(lastMsgDate);
Log.d(TAG, "SMS Push request said: status " + pushStatus + " - " + pushMessage);
}
public void doPushRequestV2(JSONArray smsList) throws OCSyncException {
}
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);
}
public GetMethod createGetLastSmsTimestampRequest() {
return createGetRequest(OC_GET_LAST_MSG_TIMESTAMP);
}
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.fetchAllMessages();
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;
ConnectivityMonitor cMon = new ConnectivityMonitor(_context);
while (tryNb < maximumHttpReqTries) {
tryNb++;
if (!cMon.isValid()) {
if (tryNb == maximumHttpReqTries) {
req.releaseConnection();
throw new OCSyncException(R.string.err_sync_no_connection_available, OCSyncErrorType.IO);
}
continue;
}
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_GET_LAST_MSG_TIMESTAMP = "/index.php/apps/ocsms/get/lastmsgtime?format=json";
private static String OC_PUSH_ROUTE = "/index.php/apps/ocsms/push?format=json";
private static final String TAG = OCSMSOwnCloudClient.class.getSimpleName();
}

View File

@ -0,0 +1,325 @@
package fr.unix_experience.owncloud_sms.engine;
/*
* Copyright (c) 2014-2015, 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) {
_lastMsgDate = (long) 0;
_context = ct;
_existingInboxMessages = null;
_existingSentMessages = null;
_existingDraftsMessages = null;
}
public JSONArray fetchAllMessages() {
_jsonDataDump = new JSONArray();
bufferizeMailboxMessages(MailboxID.INBOX);
bufferizeMailboxMessages(MailboxID.SENT);
bufferizeMailboxMessages(MailboxID.DRAFTS);
return _jsonDataDump;
}
private void bufferizeMailboxMessages(MailboxID mbID) {
String mbURI = mapMailboxIDToURI(mbID);
if (_context == null || mbURI == null) {
return;
}
if (mbID != MailboxID.INBOX && mbID != MailboxID.SENT &&
mbID != MailboxID.DRAFTS) {
Log.e(TAG,"Unhandled MailboxID " + mbID.ordinal());
return;
}
// We generate a ID list for this message box
String existingIDs = buildExistingMessagesString(mbID);
Cursor c = null;
if (existingIDs.length() > 0) {
c = (new SmsDataProvider(_context)).query(mbURI, "_id NOT IN (" + existingIDs + ")");
}
else {
c = (new SmsDataProvider(_context)).query(mbURI);
}
// Reading mailbox
if (c != null && c.getCount() > 0) {
c.moveToFirst();
do {
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));
}
// 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 {
// Special case for date, we need to record last without searching
if (colName.equals(new String("date"))) {
final Long tmpDate = c.getLong(idx);
if (tmpDate > _lastMsgDate) {
_lastMsgDate = tmpDate;
}
}
entry.put(colName, c.getString(idx));
}
}
// Mailbox ID is required by server
entry.put("mbox", mbID.ordinal());
_jsonDataDump.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 " + mbURI);
c.close();
}
}
// Used by Content Observer
public JSONArray getLastMessage(MailboxID mbID) {
String mbURI = mapMailboxIDToURI(mbID);
if (_context == null || mbURI == null) {
return null;
}
// Fetch Sent SMS Message from Built-in Content Provider
Cursor c = (new SmsDataProvider(_context)).query(mbURI);
c.moveToNext();
// We create a list of strings to store results
JSONArray results = new JSONArray();
JSONObject entry = new JSONObject();
try {
Integer mboxId = -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"))) {
entry.put(colName, 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 if (colName.equals(new String("type"))) {
mboxId = c.getInt(idx);
entry.put(colName, c.getInt(idx));
}
else {
entry.put(colName, c.getString(idx));
}
}
/*
* Mailbox ID is required by server
* mboxId is greater than server mboxId by 1 because types
* aren't indexed in the same mean
*/
entry.put("mbox", (mboxId - 1));
results.put(entry);
} catch (JSONException e) {
Log.e(TAG, "JSON Exception when reading SMS Mailbox", e);
c.close();
}
c.close();
return results;
}
// Used by ConnectivityChanged Event
public JSONArray bufferizeMessagesSinceDate(Long sinceDate) {
_jsonDataDump = new JSONArray();
bufferizeMessagesSinceDate(MailboxID.INBOX, sinceDate);
bufferizeMessagesSinceDate(MailboxID.SENT, sinceDate);
bufferizeMessagesSinceDate(MailboxID.DRAFTS, sinceDate);
return _jsonDataDump;
}
// Used by ConnectivityChanged Event
public void bufferizeMessagesSinceDate(MailboxID mbID, Long sinceDate) {
String mbURI = mapMailboxIDToURI(mbID);
if (_context == null || mbURI == null) {
return;
}
Cursor c = new SmsDataProvider(_context).query(mbURI, "date > ?", new String[] { sinceDate.toString() });
// Reading mailbox
if (c != null && c.getCount() > 0) {
c.moveToFirst();
do {
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 {
// Special case for date, we need to record last without searching
if (colName.equals(new String("date"))) {
final Long tmpDate = c.getLong(idx);
if (tmpDate > _lastMsgDate) {
_lastMsgDate = tmpDate;
}
}
entry.put(colName, c.getString(idx));
}
}
// Mailbox ID is required by server
entry.put("mbox", mbID.ordinal());
_jsonDataDump.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 " + mbURI);
c.close();
}
}
private String mapMailboxIDToURI(MailboxID mbID) {
if (mbID == MailboxID.INBOX) {
return "content://sms/inbox";
}
else if (mbID == MailboxID.DRAFTS) {
return "content://sms/drafts";
}
else if (mbID == MailboxID.SENT) {
return "content://sms/sent";
}
else if (mbID == MailboxID.ALL) {
return "content://sms";
}
return null;
}
private String buildExistingMessagesString(MailboxID _mbID) {
JSONArray existingMessages = null;
if (_mbID == MailboxID.INBOX) {
existingMessages = _existingInboxMessages;
} else if (_mbID == MailboxID.DRAFTS) {
existingMessages = _existingDraftsMessages;
} else if (_mbID == MailboxID.SENT) {
existingMessages = _existingSentMessages;
}
// Note: The default case isn't possible, we check the mailbox before
StringBuilder sb = new StringBuilder();
if (existingMessages != null) {
int len = existingMessages.length();
for (int i = 0; i < len; i++) {
try {
if (sb.length() > 0) {
sb.append(",");
}
sb.append(existingMessages.getInt(i));
} catch (JSONException e) {
}
}
}
return sb.toString();
}
public void setExistingInboxMessages(JSONArray inboxMessages) {
_existingInboxMessages = inboxMessages;
}
public void setExistingSentMessages(JSONArray sentMessages) {
_existingSentMessages = sentMessages;
}
public void setExistingDraftsMessages(JSONArray draftMessages) {
_existingDraftsMessages = draftMessages;
}
public Long getLastMessageDate() {
return _lastMsgDate;
}
private Context _context;
private JSONArray _jsonDataDump;
private JSONArray _existingInboxMessages;
private JSONArray _existingSentMessages;
private JSONArray _existingDraftsMessages;
private Long _lastMsgDate;
private static final String TAG = SmsFetcher.class.getSimpleName();
}

View File

@ -30,8 +30,6 @@ public enum LoginReturnCode {
INVALID_ADDR,
HTTP_CONN_FAILED,
CONN_FAILED,
CONN_FAILED_NOT_FOUND,
INVALID_LOGIN,
UNKNOWN_ERROR,
}

View File

@ -11,7 +11,7 @@ package fr.unix_experience.owncloud_sms.enums;
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@ -25,9 +25,9 @@ package fr.unix_experience.owncloud_sms.enums;
* SUCH DAMAGE.
*/
public enum PermissionID {
REQUEST_SMS,
REQUEST_CONTACTS,
REQUEST_ACCOUNTS,
REQUEST_MAX,
public enum MailboxID {
INBOX,
SENT,
DRAFTS,
ALL,
}

View File

@ -1,7 +1,7 @@
package fr.unix_experience.owncloud_sms.engine;
package fr.unix_experience.owncloud_sms.enums;
/*
* Copyright (c) 2014-2016, Loic Blot <loic.blot@unix-experience.fr>
* Copyright (c) 2014-2015, 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
@ -12,18 +12,13 @@ package fr.unix_experience.owncloud_sms.engine;
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
public class SmsEntry {
public int id;
public int mailboxId;
public int type;
public boolean read;
public boolean seen;
public long date;
public String address;
public String body;
public enum OCSMSNotificationType {
SYNC,
SYNC_FAILED,
DEBUG,
}

View File

@ -0,0 +1,57 @@
package fr.unix_experience.owncloud_sms.notifications;
/*
* Copyright (c) 2014-2015, 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.R;
import fr.unix_experience.owncloud_sms.enums.OCSMSNotificationType;
import android.annotation.TargetApi;
import android.app.Notification;
import android.app.Notification.Builder;
import android.app.NotificationManager;
import android.content.Context;
import android.os.Build;
public class OCSMSNotification {
public OCSMSNotification(Context ct) {
_ct = ct;
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public boolean createNotify(OCSMSNotificationType nType, String nTitle, String nText) {
if (_ct == null) {
return false;
}
NotificationManager notificationManager = (NotificationManager)_ct.getSystemService(Context.NOTIFICATION_SERVICE);
Builder mBuilder = new Notification.Builder(_ct)
.setContentText(nText)
.setContentTitle(nTitle)
.setSmallIcon(R.drawable.ic_launcher);
notificationManager.notify(nType.ordinal(), mBuilder.build());
return true;
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public void cancelNotify(OCSMSNotificationType nType) {
NotificationManager notificationManager = (NotificationManager)_ct.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(nType.ordinal());
}
private Context _ct;
}

View File

@ -0,0 +1,66 @@
package fr.unix_experience.owncloud_sms.notifications;
/*
* Copyright (c) 2014-2015, 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.R;
import fr.unix_experience.owncloud_sms.enums.OCSMSNotificationType;
import android.content.Context;
public class OCSMSNotificationManager {
public OCSMSNotificationManager(Context context) {
_context = context;
_notification = new OCSMSNotification(_context);
}
public void setSyncProcessMsg() {
createNotificationIfPossible(OCSMSNotificationType.SYNC,
_context.getString(R.string.sync_title),
_context.getString(R.string.sync_inprogress)
);
}
public void dropSyncProcessMsg() {
_notification.cancelNotify(OCSMSNotificationType.SYNC);
}
public void setSyncErrorMsg(String errMsg) {
createNotificationIfPossible(OCSMSNotificationType.SYNC_FAILED,
_context.getString(R.string.sync_title),
_context.getString(R.string.fatal_error) + "\n" + errMsg
);
}
public void dropSyncErrorMsg() {
_notification.cancelNotify(OCSMSNotificationType.SYNC_FAILED);
}
public void setDebugMsg(String errMsg) {
createNotificationIfPossible(OCSMSNotificationType.DEBUG,
"DEBUG", errMsg
);
}
private void createNotificationIfPossible(OCSMSNotificationType nType, String nTitle, String nMsg) {
_notification.createNotify(nType, nTitle, nMsg);
}
private Context _context;
private OCSMSNotification _notification;
}

View File

@ -17,55 +17,37 @@ package fr.unix_experience.owncloud_sms.observers;
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import android.Manifest;
import android.accounts.Account;
import android.accounts.AccountManager;
import org.json.JSONArray;
import fr.unix_experience.owncloud_sms.engine.ASyncTask;
import fr.unix_experience.owncloud_sms.engine.OCSMSOwnCloudClient;
import fr.unix_experience.owncloud_sms.engine.SmsFetcher;
import fr.unix_experience.owncloud_sms.enums.MailboxID;
import android.content.Context;
import android.database.ContentObserver;
import android.os.Handler;
import android.util.Log;
import fr.unix_experience.owncloud_sms.R;
import fr.unix_experience.owncloud_sms.engine.ASyncSMSSync;
import fr.unix_experience.owncloud_sms.engine.AndroidSmsFetcher;
import fr.unix_experience.owncloud_sms.engine.ConnectivityMonitor;
import fr.unix_experience.owncloud_sms.engine.OCSMSOwnCloudClient;
import fr.unix_experience.owncloud_sms.enums.MailboxID;
import fr.unix_experience.owncloud_sms.enums.PermissionID;
import fr.unix_experience.owncloud_sms.prefs.PermissionChecker;
import ncsmsgo.SmsBuffer;
public class SmsObserver extends ContentObserver implements ASyncTask {
public class SmsObserver extends ContentObserver implements ASyncSMSSync {
public SmsObserver(Handler handler, Context ct) {
public SmsObserver(Handler handler) {
super(handler);
}
public SmsObserver(Handler handler, Context ct) {
super(handler);
_context = ct;
}
public void onChange(boolean selfChange) {
if (!PermissionChecker.checkPermission(_context, Manifest.permission.READ_SMS,
PermissionID.REQUEST_SMS)) {
return;
}
super.onChange(selfChange);
Log.i(SmsObserver.TAG, "onChange SmsObserver");
// No account, abort
Account[] myAccountList = AccountManager.get(_context).
getAccountsByType(_context.getString(R.string.account_type));
if (myAccountList.length == 0) {
return;
}
Log.d(TAG, "onChange SmsObserver");
AndroidSmsFetcher fetcher = new AndroidSmsFetcher(_context);
SmsBuffer smsBuffer = fetcher.getLastMessage(MailboxID.ALL);
SmsFetcher fetcher = new SmsFetcher(_context);
JSONArray smsList = fetcher.getLastMessage(MailboxID.ALL);
ConnectivityMonitor cMon = new ConnectivityMonitor(_context);
// Synchronize if network is valid and there are SMS
if (cMon.isValid() && (smsBuffer != null)) {
new SyncTask(_context, smsBuffer).execute();
if (smsList != null) {
new SyncTask(_context, smsList).execute();
}
}

View File

@ -1,4 +1,4 @@
package fr.unix_experience.owncloud_sms.enums;
package fr.unix_experience.owncloud_sms.prefs;
/*
* Copyright (c) 2014-2015, Loic Blot <loic.blot@unix-experience.fr>
@ -12,29 +12,33 @@ package fr.unix_experience.owncloud_sms.enums;
* 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(OCSMSNotificationChannel.SYNC, 0),
SYNC_FAILED(OCSMSNotificationChannel.DEFAULT, 1),
PERMISSION(OCSMSNotificationChannel.DEFAULT, 2);
import fr.unix_experience.owncloud_sms.R;
import android.content.Context;
import android.content.SharedPreferences;
private final OCSMSNotificationChannel channel;
private final int notificationId;
public class OCSMSSharedPrefs {
OCSMSNotificationType(OCSMSNotificationChannel channel, int notificationId) {
this.channel = channel;
this.notificationId = notificationId;
public OCSMSSharedPrefs(Context context) {
_context = context;
_sPrefs = _context.getSharedPreferences(_context.getString(R.string.shared_preference_file), Context.MODE_PRIVATE);
}
public OCSMSNotificationChannel getChannel() {
return channel;
public void setLastMessageDate(Long msgDate) {
SharedPreferences.Editor editor = _sPrefs.edit();
editor.putLong(_context.getString(R.string.pref_lastmsgdate), msgDate);
editor.commit();
}
public int getNotificationId() {
return notificationId;
public Long getLastMessageDate() {
return _sPrefs.getLong(_context.getString(R.string.pref_lastmsgdate), 0);
}
private SharedPreferences _sPrefs;
private Context _context;
}

View File

@ -0,0 +1,98 @@
package fr.unix_experience.owncloud_sms.providers;
/*
* Copyright (c) 2014-2015, 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.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
public class SmsDataProvider extends ContentProvider {
public SmsDataProvider () {}
public SmsDataProvider (Context ct) {
super();
_context = ct;
}
@Override
public boolean onCreate() {
return false;
}
public Cursor query(String mailBox) {
return query(Uri.parse(mailBox),
new String[] { "read", "date", "address", "seen", "body", "_id", "type", },
null, null, null
);
}
public Cursor query(String mailBox, String selection) {
return query(Uri.parse(mailBox),
new String[] { "read", "date", "address", "seen", "body", "_id", "type", },
selection, null, null
);
}
public Cursor query(String mailBox, String selection, String[] selectionArgs) {
return query(Uri.parse(mailBox),
new String[] { "read", "date", "address", "seen", "body", "_id", "type", },
selection, selectionArgs, null
);
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
if (_context != null && _context.getContentResolver() != null) {
return _context.getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder);
}
return null;
}
@Override
public String getType(Uri uri) {
// TODO Auto-generated method stub
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
// TODO Auto-generated method stub
return null;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// TODO Auto-generated method stub
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
// TODO Auto-generated method stub
return 0;
}
private Context _context;
}

View File

@ -1,4 +1,4 @@
package fr.unix_experience.owncloud_sms.enums;
package fr.unix_experience.owncloud_sms.sync_adapters;
/*
* Copyright (c) 2014-2015, Loic Blot <loic.blot@unix-experience.fr>
@ -25,34 +25,44 @@ package fr.unix_experience.owncloud_sms.enums;
* SUCH DAMAGE.
*/
public enum MailboxID {
INBOX(0),
SENT(1),
DRAFTS(2),
ALL(3);
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
MailboxID(int id) {
switch (id) {
case 0: uri = "content://sms/inbox"; break;
case 1: uri = "content://sms/sent"; break;
case 2: uri = "content://sms/drafts"; break;
case 3: uri = "content://sms"; break;
default: throw new AssertionError();
}
this.id = id;
}
public static MailboxID fromInt(int id) {
switch (id) {
case 0: return MailboxID.INBOX;
case 1: return MailboxID.SENT;
case 2: return MailboxID.DRAFTS;
case 3: return MailboxID.ALL;
default: throw new AssertionError();
}
}
private final String uri;
private final int id;
public int getId() { return id; }
public String getURI() { return uri; }
public class SmsSlowSyncService extends Service {
// Storage for an instance of the sync adapter
private static SmsSyncAdapter _adapter = null;
// Object to use as a thread-safe lock
private static final Object sSyncAdapterLock = new Object();
/*
* Instantiate the sync adapter object.
*/
@Override
public void onCreate() {
/*
* Create the sync adapter as a singleton.
* Set the sync adapter as syncable
* Disallow parallel syncs
*/
synchronized (sSyncAdapterLock) {
if (_adapter == null) {
_adapter = new SmsSyncAdapter(getApplicationContext(), true);
}
}
}
/**
* Return an object that allows the system to invoke
* the sync adapter.
*
*/
@Override
public IBinder onBind(Intent intent) {
/*
* Get the object that allows external processes
* to call onPerformSync(). The object is created
* in the base class code when the SyncAdapter
* constructors call super()
*/
return _adapter.getSyncAdapterBinder();
}
}

View File

@ -12,57 +12,63 @@ package fr.unix_experience.owncloud_sms.sync_adapters;
* 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.R;
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;
import fr.unix_experience.owncloud_sms.R;
import fr.unix_experience.owncloud_sms.engine.OCSMSOwnCloudClient;
import fr.unix_experience.owncloud_sms.enums.OCSMSNotificationType;
import fr.unix_experience.owncloud_sms.enums.OCSyncErrorType;
import fr.unix_experience.owncloud_sms.exceptions.OCSyncException;
import fr.unix_experience.owncloud_sms.notifications.OCSMSNotificationUI;
import fr.unix_experience.owncloud_sms.prefs.OCSMSSharedPrefs;
public class SmsSyncAdapter extends AbstractThreadedSyncAdapter {
class SmsSyncAdapter extends AbstractThreadedSyncAdapter {
SmsSyncAdapter(Context context, boolean autoInitialize) {
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) {
if (new OCSMSSharedPrefs(getContext()).showSyncNotifications()) {
OCSMSNotificationUI.notify(getContext(), getContext().getString(R.string.sync_title),
getContext().getString(R.string.sync_inprogress), OCSMSNotificationType.SYNC);
ContentProviderClient provider, SyncResult syncResult) {
OCSMSNotificationManager nMgr = new OCSMSNotificationManager(getContext());
// Create client
String ocURI = _accountMgr.getUserData(account, "ocURI");
if (ocURI == null) {
nMgr.setSyncErrorMsg(getContext().getString(R.string.err_sync_account_unparsable));
return;
}
Uri serverURI = Uri.parse(ocURI);
nMgr.setSyncProcessMsg();
OCSMSOwnCloudClient _client = new OCSMSOwnCloudClient(getContext(),
serverURI, _accountMgr.getUserData(account, "ocLogin"),
_accountMgr.getPassword(account));
try {
OCSMSOwnCloudClient _client = new OCSMSOwnCloudClient(getContext(), account);
// getServerAPI version
Log.i(SmsSyncAdapter.TAG, "Server API version: " + _client.getServerAPIVersion());
Log.d(TAG,"Server API version: " + _client.getServerAPIVersion());
// and push datas
_client.doPushRequest(null);
OCSMSNotificationUI.cancel(getContext(), OCSMSNotificationType.SYNC_FAILED);
} catch (IllegalStateException e) {
OCSMSNotificationUI.notify(getContext(), getContext().getString(R.string.fatal_error),
e.getMessage(), OCSMSNotificationType.SYNC_FAILED);
nMgr.dropSyncErrorMsg();
} catch (OCSyncException e) {
OCSMSNotificationUI.notify(getContext(), getContext().getString(R.string.fatal_error),
getContext().getString(e.getErrorId()), OCSMSNotificationType.SYNC_FAILED);
nMgr.setSyncErrorMsg(getContext().getString(e.getErrorId()));
if (e.getErrorType() == OCSyncErrorType.IO) {
syncResult.stats.numIoExceptions++;
}
@ -73,12 +79,15 @@ class SmsSyncAdapter extends AbstractThreadedSyncAdapter {
syncResult.stats.numAuthExceptions++;
}
else {
Log.w(SmsSyncAdapter.TAG, "onPerformSync: unhandled response");
// UNHANDLED
}
} finally {
OCSMSNotificationUI.cancel(getContext(), OCSMSNotificationType.SYNC);
}
nMgr.dropSyncProcessMsg();
}
private AccountManager _accountMgr;
private static final String TAG = SmsSyncAdapter.class.getSimpleName();
}

View File

@ -44,9 +44,9 @@ public class SmsSyncService extends Service {
* Set the sync adapter as syncable
* Disallow parallel syncs
*/
synchronized (SmsSyncService.sSyncAdapterLock) {
if (SmsSyncService._adapter == null) {
SmsSyncService._adapter = new SmsSyncAdapter(getApplicationContext(), true);
synchronized (sSyncAdapterLock) {
if (_adapter == null) {
_adapter = new SmsSyncAdapter(getApplicationContext(), true);
}
}
}
@ -63,6 +63,6 @@ public class SmsSyncService extends Service {
* in the base class code when the SyncAdapter
* constructors call super()
*/
return SmsSyncService._adapter.getSyncAdapterBinder();
return _adapter.getSyncAdapterBinder();
}
}

View File

@ -1,167 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="fr.unix_experience.owncloud_sms"> <!-- From Android 4.1 to O -->
<uses-sdk android:maxSdkVersion="26" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.WRITE_SMS" />
<!-- For SMS Restore & Sending -->
<uses-permission android:name="android.permission.SEND_SMS" />
<!-- For SMS Broadcaster -->
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 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" />
<!-- For backup restauration -->
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:theme="@style/OcSmsTheme">
<!-- Related to periodic sync -->
<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="@string/account_authority"
android:label="@string/pref_title_sync"></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"
android:permission="android.permission.BROADCAST_SMS">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
<action android:name="android.provider.Telephony.SMS_DELIVER" />
</intent-filter>
</receiver>
<!-- BroadcastReceiver that listens for incoming MMS messages. Note: useless class, used only for restoring SMS -->
<receiver
android:name=".misc.MmsReceiver"
android:permission="android.permission.BROADCAST_WAP_PUSH">
<intent-filter>
<action android:name="android.provider.Telephony.WAP_PUSH_DELIVER" />
<data android:mimeType="application/vnd.wap.mms-message" />
</intent-filter>
</receiver>
<!-- Activity that allows the user to send new SMS/MMS messages Note: useless class, used only for restoring SMS -->
<activity android:name=".misc.ComposeSmsActivity">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<action android:name="android.intent.action.SENDTO" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="sms" />
<data android:scheme="smsto" />
<data android:scheme="mms" />
<data android:scheme="mmsto" />
</intent-filter>
</activity>
<!-- Service that delivers messages from the phone "quick response" Note: useless class, used only for restoring SMS -->
<service
android:name=".misc.HeadlessSmsSendService"
android:exported="true"
android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE">
<intent-filter>
<action android:name="android.intent.action.RESPOND_VIA_MESSAGE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="sms" />
<data android:scheme="smsto" />
<data android:scheme="mms" />
<data android:scheme="mmsto" />
</intent-filter>
</service>
<receiver android:name=".broadcast_receivers.ConnectivityChanged">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
<activity
android:name=".activities.LoginActivity"
android:label="@string/title_activity_login"
android:theme="@style/OcSmsTheme.Login"></activity>
<activity
android:name=".activities.remote_account.AccountListActivity"
android:label="@string/title_activity_select_account"></activity>
<activity
android:name=".activities.OCSMSSettingsActivity"
android:label="@string/title_activity_general_settings"></activity>
<activity
android:name=".activities.MainActivity"
android:label="@string/app_name"
android:theme="@style/OcSmsTheme.Drawer">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".activities.remote_account.ContactListActivity"
android:label="@string/title_activity_select_contact"></activity>
<activity
android:name=".activities.remote_account.AccountActionsActivity"
android:label="@string/account_actions"></activity>
<activity
android:name=".activities.remote_account.RestoreMessagesActivity"
android:label="@string/restore_all_messages"></activity>
<activity
android:name=".activities.PrivacyPolicyActivity"
android:label="@string/action_appinfo_privacy_policy"
android:theme="@style/OcSmsTheme.NoActionBar"></activity>
</application>
</manifest>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

View File

@ -1,292 +0,0 @@
package fr.unix_experience.android_lib;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListAdapter;
import android.widget.ListView;
import fr.unix_experience.owncloud_sms.R;
/**
* An activity that displays a list of items by binding to a data source such as
* an array or Cursor, and exposes event handlers when the user selects an item.
* <p>
* ListActivity hosts a {@link android.widget.ListView ListView} object that can
* be bound to different data sources, typically either an array or a Cursor
* holding query results. Binding, screen layout, and row layout are discussed
* in the following sections.
* <p>
* <strong>Screen Layout</strong>
* </p>
* <p>
* ListActivity has a default layout that consists of a single, full-screen list
* in the center of the screen. However, if you desire, you can customize the
* screen layout by setting your own view layout with setContentView() in
* onCreate(). To do this, your own view MUST contain a ListView object with the
* id "@android:id/list" (or {@link android.R.id#list} if it's in code)
* <p>
* Optionally, your custom view can contain another view object of any type to
* display when the list view is empty. This "empty list" notifier must have an
* id "android:id/empty". Note that when an empty view is present, the list view
* will be hidden when there is no data to display.
* <p>
* The following code demonstrates an (ugly) custom screen layout. It has a list
* with a green background, and an alternate red "no data" message.
* </p>
*
* <pre>
* &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
* &lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
* android:orientation=&quot;vertical&quot;
* android:layout_width=&quot;match_parent&quot;
* android:layout_height=&quot;match_parent&quot;
* android:paddingLeft=&quot;8dp&quot;
* android:paddingRight=&quot;8dp&quot;&gt;
*
* &lt;ListView android:id=&quot;@android:id/list&quot;
* android:layout_width=&quot;match_parent&quot;
* android:layout_height=&quot;match_parent&quot;
* android:background=&quot;#00FF00&quot;
* android:layout_weight=&quot;1&quot;
* android:drawSelectorOnTop=&quot;false&quot;/&gt;
*
* &lt;TextView android:id=&quot;@android:id/empty&quot;
* android:layout_width=&quot;match_parent&quot;
* android:layout_height=&quot;match_parent&quot;
* android:background=&quot;#FF0000&quot;
* android:text=&quot;No data&quot;/&gt;
* &lt;/LinearLayout&gt;
* </pre>
*
* <p>
* <strong>Row Layout</strong>
* </p>
* <p>
* You can specify the layout of individual rows in the list. You do this by
* specifying a layout resource in the ListAdapter object hosted by the activity
* (the ListAdapter binds the ListView to the data; more on this later).
* <p>
* A ListAdapter constructor takes a parameter that specifies a layout resource
* for each row. It also has two additional parameters that let you specify
* which data field to associate with which object in the row layout resource.
* These two parameters are typically parallel arrays.
* </p>
* <p>
* Android provides some standard row layout resources. These are in the
* {@link android.R.layout} class, and have names such as simple_list_item_1,
* simple_list_item_2, and two_line_list_item. The following layout XML is the
* source for the resource two_line_list_item, which displays two data
* fields,one above the other, for each list row.
* </p>
*
* <pre>
* &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
* &lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
* android:layout_width=&quot;match_parent&quot;
* android:layout_height=&quot;wrap_content&quot;
* android:orientation=&quot;vertical&quot;&gt;
*
* &lt;TextView android:id=&quot;@+id/text1&quot;
* android:textSize=&quot;16sp&quot;
* android:textStyle=&quot;bold&quot;
* android:layout_width=&quot;match_parent&quot;
* android:layout_height=&quot;wrap_content&quot;/&gt;
*
* &lt;TextView android:id=&quot;@+id/text2&quot;
* android:textSize=&quot;16sp&quot;
* android:layout_width=&quot;match_parent&quot;
* android:layout_height=&quot;wrap_content&quot;/&gt;
* &lt;/LinearLayout&gt;
* </pre>
*
* <p>
* You must identify the data bound to each TextView object in this layout. The
* syntax for this is discussed in the next section.
* </p>
* <p>
* <strong>Binding to Data</strong>
* </p>
* <p>
* You bind the ListActivity's ListView object to data using a class that
* implements the {@link android.widget.ListAdapter ListAdapter} interface.
* Android provides two standard list adapters:
* {@link android.widget.SimpleAdapter SimpleAdapter} for static data (Maps),
* and {@link android.widget.SimpleCursorAdapter SimpleCursorAdapter} for Cursor
* query results.
* </p>
* <p>
* The following code from a custom ListActivity demonstrates querying the
* Contacts provider for all contacts, then binding the Name and Company fields
* to a two line row layout in the activity's ListView.
* </p>
*
* <pre>
* public class MyListAdapter extends ListActivity {
*
* &#064;Override
* protected void onCreate(Bundle savedInstanceState){
* super.onCreate(savedInstanceState);
*
* // We'll define a custom screen layout here (the one shown above), but
* // typically, you could just use the standard ListActivity layout.
* setContentView(R.layout.custom_list_activity_view);
*
* // Query for all people contacts using the {@link android.provider.Contacts.People} convenience class.
* // Put a managed wrapper around the retrieved cursor so we don't have to worry about
* // requerying or closing it as the activity changes state.
* mCursor = this.getContentResolver().query(People.CONTENT_URI, null, null, null, null);
* startManagingCursor(mCursor);
*
* // Now create a new list adapter bound to the cursor.
* // SimpleListAdapter is designed for binding to a Cursor.
* ListAdapter adapter = new SimpleCursorAdapter(
* this, // Context.
* android.R.layout.two_line_list_item, // Specify the row template to use (here, two columns bound to the two retrieved cursor
* rows).
* mCursor, // Pass in the cursor to bind to.
* new String[] {People.NAME, People.COMPANY}, // Array of cursor columns to bind to.
* new int[] {android.R.id.text1, android.R.id.text2}); // Parallel array of which template objects to bind to those columns.
*
* // Bind to our new adapter.
* setListAdapter(adapter);
* }
* }
* </pre>
*
* @see #setListAdapter
* @see android.widget.ListView
*/
public class AppCompatListActivity extends AppCompatActivity {
protected ListAdapter mAdapter;
protected ListView mList;
private Handler mHandler = new Handler();
private boolean mFinishedStart = false;
private Runnable mRequestFocus = new Runnable() {
public void run() {
mList.focusableViewAvailable(mList);
}
};
protected void onListItemClick(ListView l, View v, int position, long id) {
}
/**
* Ensures the list view has been created before Activity restores all
* of the view states.
*
*@see Activity#onRestoreInstanceState(Bundle)
*/
@Override
protected void onRestoreInstanceState(Bundle state) {
ensureList();
super.onRestoreInstanceState(state);
}
/**
* @see Activity#onDestroy()
*/
@Override
protected void onDestroy() {
mHandler.removeCallbacks(mRequestFocus);
super.onDestroy();
}
/**
* Updates the screen state (current list and other views) when the
* content changes.
*
* @see Activity#onContentChanged()
*/
@Override
public void onContentChanged() {
super.onContentChanged();
View emptyView = findViewById(R.id.empty);
mList = findViewById(R.id.list);
if (mList == null) {
throw new RuntimeException(
"Your content must have a ListView whose id attribute is " +
"'android.R.id.list'");
}
if (emptyView != null) {
mList.setEmptyView(emptyView);
}
mList.setOnItemClickListener(mOnClickListener);
if (mFinishedStart) {
setListAdapter(mAdapter);
}
mHandler.post(mRequestFocus);
mFinishedStart = true;
}
/**
* Provide the cursor for the list view.
*/
public void setListAdapter(ListAdapter adapter) {
synchronized (this) {
ensureList();
mAdapter = adapter;
mList.setAdapter(adapter);
}
}
/**
* Set the currently selected list item to the specified
* position with the adapter's data
*
* @param position
*/
public void setSelection(int position) {
mList.setSelection(position);
}
/**
* Get the position of the currently selected list item.
*/
public int getSelectedItemPosition() {
return mList.getSelectedItemPosition();
}
/**
* Get the cursor row ID of the currently selected list item.
*/
public long getSelectedItemId() {
return mList.getSelectedItemId();
}
/**
* Get the activity's list view widget.
*/
public ListView getListView() {
ensureList();
return mList;
}
/**
* Get the ListAdapter associated with this activity's ListView.
*/
public ListAdapter getListAdapter() {
return mAdapter;
}
private void ensureList() {
if (mList != null) {
return;
}
setContentView(R.layout.default_list);
}
private AdapterView.OnItemClickListener mOnClickListener = new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v, int position, long id)
{
onListItemClick((ListView)parent, v, position, id);
}
};
}

View File

@ -1,279 +0,0 @@
package fr.unix_experience.owncloud_sms.activities;
/*
* Copyright (c) 2014-2016, Loic Blot <loic.blot@unix-experience.fr>
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.design.widget.NavigationView;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.MenuItem;
import android.view.Window;
import android.widget.Toast;
import fr.unix_experience.owncloud_sms.R;
import fr.unix_experience.owncloud_sms.activities.remote_account.AccountListActivity;
import fr.unix_experience.owncloud_sms.engine.ASyncSMSSync.SyncTask;
import fr.unix_experience.owncloud_sms.engine.ConnectivityMonitor;
import fr.unix_experience.owncloud_sms.enums.PermissionID;
import fr.unix_experience.owncloud_sms.prefs.PermissionChecker;
import static fr.unix_experience.owncloud_sms.enums.PermissionID.REQUEST_MAX;
import static fr.unix_experience.owncloud_sms.enums.PermissionID.REQUEST_SMS;
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
private ConnectivityMonitor _ConnectivityMonitor = null;
private DrawerLayout drawer;
@Override
protected void onCreate(Bundle savedInstanceState) {
if (_ConnectivityMonitor == null) {
_ConnectivityMonitor = new ConnectivityMonitor(getApplicationContext());
}
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setupToolbar();
if (getSupportActionBar() != null) {
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
drawer = findViewById(R.id.drawer_layout);
setupDrawer();
drawer.openDrawer(GravityCompat.START);
}
protected void setupToolbar() {
setSupportActionBar((Toolbar) findViewById(R.id.toolbar));
}
private void setupDrawer() {
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, null, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
assert drawer != null;
drawer.addDrawerListener(toggle);
toggle.syncState();
toggle.setDrawerIndicatorEnabled(true);
NavigationView navigationView = findViewById(R.id.nav_view);
assert navigationView != null;
navigationView.setNavigationItemSelectedListener(this);
}
/**
* checks if the drawer exists and is opened.
*
* @return <code>true</code> if the drawer is open, else <code>false</code>
*/
public boolean isDrawerOpen() {
return drawer != null && drawer.isDrawerOpen(GravityCompat.START);
}
/**
* closes the drawer.
*/
public void closeDrawer() {
if (drawer != null) {
drawer.closeDrawer(GravityCompat.START);
}
}
/**
* opens the drawer.
*/
public void openDrawer() {
if (drawer != null) {
drawer.openDrawer(GravityCompat.START);
}
}
@Override
public void onBackPressed() {
if (isDrawerOpen()) {
closeDrawer();
} else {
super.onBackPressed();
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
boolean retval = true;
switch (item.getItemId()) {
case android.R.id.home: {
if (isDrawerOpen()) {
closeDrawer();
} else {
openDrawer();
}
break;
}
default:
retval = super.onOptionsItemSelected(item);
}
return retval;
}
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
int id = item.getItemId();
boolean res = true;
switch (id) {
case R.id.nav_sync:
syncAllMessages();
break;
case R.id.nav_manage:
res = openAppSettings();
break;
case R.id.nav_rateus:
res = openGooglePlayStore();
break;
case R.id.nav_add_account:
res = openAddAccount();
break;
case R.id.nav_my_accounts:
res = openMyAccounts();
break;
case R.id.nav_appinfo_perms:
res = openAppInfos();
break;
case R.id.nav_appinfo_privacy_policy:
res = openPrivacyPolicy();
break;
default:
Log.e(TAG, "Unhandled navigation item " + Integer.toString(id));
}
closeDrawer();
return res;
}
private boolean openAppSettings() {
startActivity(new Intent(this, OCSMSSettingsActivity.class));
return true;
}
private boolean openAddAccount() {
startActivity(new Intent(Settings.ACTION_ADD_ACCOUNT));
return true;
}
public void syncAllMessages() {
Log.v(MainActivity.TAG, "Launch syncAllMessages()");
if (!PermissionChecker.checkPermission(this, Manifest.permission.READ_SMS,
REQUEST_SMS)) {
return;
}
Context ctx = getApplicationContext();
if (!_ConnectivityMonitor.isValid()) {
Toast.makeText(ctx, ctx.getString(R.string.err_sync_no_connection_available), Toast.LENGTH_SHORT).show();
Log.v(MainActivity.TAG, "Finish syncAllMessages(): invalid connection");
return;
}
new SyncTask(this).execute();
Log.v(MainActivity.TAG, "Finish syncAllMessages()");
}
private boolean openMyAccounts() {
startActivity(new Intent(this, AccountListActivity.class));
return true;
}
private boolean openGooglePlayStore() {
Intent intent;
try {
intent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + getPackageName()));
} catch (android.content.ActivityNotFoundException e) {
intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + getPackageName()));
}
startActivity(intent);
return true;
}
private boolean openAppInfos() {
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", getPackageName(), null);
intent.setData(uri);
startActivity(intent);
return true;
}
private boolean openPrivacyPolicy() {
startActivity(new Intent(this, PrivacyPolicyActivity.class));
return true;
}
/*
* Permissions
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
PermissionID requestCodeID = REQUEST_MAX;
if ((requestCode > 0) || (requestCode < REQUEST_MAX.ordinal())) {
requestCodeID = PermissionID.values()[requestCode];
}
switch (requestCodeID) {
case REQUEST_SMS:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
syncAllMessages();
} else {
// Permission Denied
Toast.makeText(this, getString(R.string.err_cannot_read_sms) + " " +
getString(R.string.please_fix_it), Toast.LENGTH_SHORT)
.show();
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
private static final String TAG = MainActivity.class.getSimpleName();
}

View File

@ -1,189 +0,0 @@
package fr.unix_experience.owncloud_sms.activities;
/*
* Copyright (c) 2014-2017, Loic Blot <loic.blot@unix-experience.fr>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import android.Manifest;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.ContentResolver;
import android.content.PeriodicSync;
import android.os.Bundle;
import android.preference.ListPreference;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatDelegate;
import android.util.Log;
import android.util.Pair;
import android.view.MenuItem;
import java.util.List;
import java.util.Vector;
import fr.unix_experience.owncloud_sms.R;
import fr.unix_experience.owncloud_sms.activities.virtual.VirtualSettingsActivity;
import fr.unix_experience.owncloud_sms.defines.DefaultPrefs;
import fr.unix_experience.owncloud_sms.prefs.OCSMSSharedPrefs;
import fr.unix_experience.owncloud_sms.prefs.PermissionChecker;
import static fr.unix_experience.owncloud_sms.enums.PermissionID.REQUEST_ACCOUNTS;
public class OCSMSSettingsActivity extends VirtualSettingsActivity {
private static final String TAG = OCSMSSettingsActivity.class.getSimpleName();
private static AccountManager _accountMgr;
private static String _accountAuthority;
private static String _accountType;
private static Vector<Pair<Integer, Boolean>> _boolSettings;
private AppCompatDelegate mDelegate;
@SuppressWarnings("deprecation")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
}
private AppCompatDelegate getDelegate() {
if (mDelegate == null) {
mDelegate = AppCompatDelegate.create(this, null);
}
return mDelegate;
}
public ActionBar getSupportActionBar() {
return getDelegate().getSupportActionBar();
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
OCSMSSettingsActivity._accountMgr = AccountManager.get(getBaseContext());
OCSMSSettingsActivity._accountAuthority = getString(R.string.account_authority);
OCSMSSettingsActivity._accountType = getString(R.string.account_type);
VirtualSettingsActivity._prefsRessourceFile = R.xml.pref_data_sync;
// Bind our boolean preferences
VirtualSettingsActivity._boolPrefs.add(
new BindObjectPref(R.string.setting_push_on_receive, DefaultPrefs.pushOnReceive));
VirtualSettingsActivity._boolPrefs.add(
new BindObjectPref(R.string.setting_show_sync_notifications, DefaultPrefs.showSyncNotifications));
VirtualSettingsActivity._boolPrefs.add(
new BindObjectPref(R.string.setting_sync_wifi, DefaultPrefs.syncWifi));
VirtualSettingsActivity._boolPrefs.add(
new BindObjectPref(R.string.setting_sync_4g, DefaultPrefs.sync4G));
VirtualSettingsActivity._boolPrefs.add(
new BindObjectPref(R.string.setting_sync_3g, DefaultPrefs.sync3G));
VirtualSettingsActivity._boolPrefs.add(
new BindObjectPref(R.string.setting_sync_gprs, DefaultPrefs.syncGPRS));
VirtualSettingsActivity._boolPrefs.add(
new BindObjectPref(R.string.setting_sync_2g, DefaultPrefs.sync2G));
VirtualSettingsActivity._boolPrefs.add(
new BindObjectPref(R.string.setting_sync_others, DefaultPrefs.syncOthers));
// Bind our string preferences
VirtualSettingsActivity._stringPrefs.add(
new BindObjectPref(R.string.setting_sync_frequency, "15"));
VirtualSettingsActivity._stringPrefs.add(
new BindObjectPref(R.string.setting_sync_bulk_messages, "-1"));
VirtualSettingsActivity._stringPrefs.add(
new BindObjectPref(R.string.setting_minimum_sync_chars, "1"));
// Must be at the end, after preference bind
super.onPostCreate(savedInstanceState);
}
protected void handleCheckboxPreference(String key, Boolean value) {
// Network types allowed for sync
if ("push_on_receive".equals(key) || "show_sync_notifications".equals(key) ||
"sync_wifi".equals(key) || "sync_2g".equals(key) ||
"sync_3g".equals(key) || "sync_gprs".equals(key) ||
"sync_4g".equals(key) || "sync_others".equals(key)) {
OCSMSSharedPrefs prefs = new OCSMSSharedPrefs(VirtualSettingsActivity._context);
Log.i(OCSMSSettingsActivity.TAG, "OCSMSSettingsActivity.handleCheckboxPreference: set " + key + " to "
+ value.toString());
prefs.putBoolean(key, value);
}
}
protected void handleListPreference(String key, String value,
ListPreference preference) {
// For list preferences, look up the correct display value in
// the preference's 'entries' list.
int index = preference.findIndexOfValue(value);
// Set the summary to reflect the new value.
preference.setSummary((index >= 0) ? preference.getEntries()[index] : null);
Log.i(OCSMSSettingsActivity.TAG, "Modifying listPreference " + key);
OCSMSSharedPrefs prefs = new OCSMSSharedPrefs(VirtualSettingsActivity._context);
// Handle sync frequency change
if ("sync_frequency".equals(key)) {
if (!PermissionChecker.checkPermission(this, Manifest.permission.GET_ACCOUNTS,
REQUEST_ACCOUNTS)) {
return;
}
Account[] myAccountList = OCSMSSettingsActivity._accountMgr.getAccountsByType(OCSMSSettingsActivity._accountType);
long syncFreq = Long.parseLong(value);
// Get ownCloud SMS account list
for (Account acct : myAccountList) {
// And get all authorities for this account
List<PeriodicSync> syncList = ContentResolver.getPeriodicSyncs(acct, OCSMSSettingsActivity._accountAuthority);
boolean foundSameSyncCycle = false;
for (PeriodicSync ps : syncList) {
if ((ps.period == syncFreq) && (ps.extras.getInt("synctype") == 1)) {
foundSameSyncCycle = true;
}
}
if (!foundSameSyncCycle) {
Bundle b = new Bundle();
b.putInt("synctype", 1);
ContentResolver.removePeriodicSync(acct, OCSMSSettingsActivity._accountAuthority, b);
if (syncFreq > 0) {
ContentResolver.addPeriodicSync(acct, OCSMSSettingsActivity._accountAuthority, b, syncFreq * 60);
}
}
prefs.putLong(key, syncFreq);
}
} else if ("sync_bulk_messages".equals(key) || "minimum_sync_chars".equals(key)) {
prefs.putInteger(key, Integer.parseInt(value));
}
}
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
super.onMenuItemSelected(featureId, item);
switch (item.getItemId()) {
case android.R.id.home:
onBackPressed();
break;
default:
return false;
}
return true;
}
}

View File

@ -1,21 +0,0 @@
package fr.unix_experience.owncloud_sms.activities;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import fr.unix_experience.owncloud_sms.R;
public class PrivacyPolicyActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_privacy_policy);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
}
}

View File

@ -1,95 +0,0 @@
package fr.unix_experience.owncloud_sms.activities.remote_account;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.ActionBar;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import java.util.ArrayList;
import fr.unix_experience.android_lib.AppCompatListActivity;
import fr.unix_experience.owncloud_sms.R;
import fr.unix_experience.owncloud_sms.prefs.OCSMSSharedPrefs;
public class AccountActionsActivity extends AppCompatListActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_account_actions);
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
ArrayList<String> itemList = new ArrayList<>();
ArrayAdapter<String> adp = new ArrayAdapter<>(getBaseContext(),
android.R.layout.simple_dropdown_item_1line, itemList);
setListAdapter(adp);
// Create item list
itemList.add(getBaseContext().getString(R.string.restore_all_messages));
itemList.add(getBaseContext().getString(R.string.reinit_sync_cursor));
adp.notifyDataSetChanged();
// Fetch account name from intent
_accountName = getIntent().getStringExtra("account");
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
boolean retval = true;
switch (item.getItemId()) {
case android.R.id.home:
finish();
break;
default:
retval = super.onOptionsItemSelected(item);
}
return retval;
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
switch (position) {
case 0:
Intent intent = new Intent(this, RestoreMessagesActivity.class);
intent.putExtra("account", _accountName);
try {
startActivity(intent);
}
catch (IllegalStateException e) {
Log.e(AccountActionsActivity.TAG, e.getMessage());
}
break;
case 1:
final Context me = this;
new AlertDialog.Builder(this)
.setIcon(android.R.drawable.ic_dialog_alert)
.setTitle(R.string.reinit_sync_cursor)
.setMessage(R.string.reinit_sync_cursor_confirm)
.setPositiveButton(R.string.yes_confirm, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
(new OCSMSSharedPrefs(me)).setLastMessageDate(0L);
Log.i(AccountActionsActivity.TAG, "Synchronization cursor reinitialized");
}
})
.setNegativeButton(R.string.no_confirm, null)
.show();
break;
default: break; // Unhandled
}
}
private String _accountName = "";
private static final String TAG = AccountActionsActivity.class.getSimpleName();
}

View File

@ -1,56 +0,0 @@
package fr.unix_experience.owncloud_sms.activities.remote_account;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.os.Bundle;
import android.view.MenuItem;
import java.util.ArrayList;
import java.util.Collections;
import fr.unix_experience.android_lib.AppCompatListActivity;
import fr.unix_experience.owncloud_sms.R;
import fr.unix_experience.owncloud_sms.adapters.AndroidAccountAdapter;
public class AccountListActivity extends AppCompatListActivity {
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
AccountManager _accountMgr = AccountManager.get(getBaseContext());
setContentView(R.layout.restore_activity_accountlist);
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
ArrayList<Account> itemList = new ArrayList<>();
AndroidAccountAdapter adapter = new AndroidAccountAdapter(this,
android.R.layout.simple_list_item_1,
itemList,
R.layout.account_list_item,
R.id.accountname, AccountActionsActivity.class);
setListAdapter(adapter);
Account[] accountList =
_accountMgr.getAccountsByType(getString(R.string.account_type));
Collections.addAll(itemList, accountList);
adapter.notifyDataSetChanged();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
onBackPressed();
break;
default:
return super.onOptionsItemSelected(item);
}
return true;
}
}

View File

@ -1,219 +0,0 @@
package fr.unix_experience.owncloud_sms.activities.remote_account;
import android.Manifest;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.Bundle;
import android.os.Handler;
import android.provider.ContactsContract;
import android.support.annotation.NonNull;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.Spinner;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.Vector;
import fr.unix_experience.owncloud_sms.R;
import fr.unix_experience.owncloud_sms.adapters.ContactListAdapter;
import fr.unix_experience.owncloud_sms.adapters.RecoveryPhoneNumberListViewAdapter;
import fr.unix_experience.owncloud_sms.engine.ASyncContactLoad;
import fr.unix_experience.owncloud_sms.enums.PermissionID;
import fr.unix_experience.owncloud_sms.prefs.PermissionChecker;
import static fr.unix_experience.owncloud_sms.enums.PermissionID.REQUEST_CONTACTS;
import static fr.unix_experience.owncloud_sms.enums.PermissionID.REQUEST_MAX;
public class ContactListActivity extends AppCompatActivity implements ASyncContactLoad {
static AccountManager mAccountMgr;
ContactListAdapter mAdapter = null;
SwipeRefreshLayout mLayout = null;
LinearLayout mContactInfos = null;
ArrayList<String> mObjects;
String mFetchedContact;
RecoveryPhoneNumberListViewAdapter mContactPhoneListAdapter = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
assert getIntent().getExtras() != null;
ContactListActivity.mAccountMgr = AccountManager.get(getBaseContext());
// Init view
mObjects = new ArrayList<>();
setContentView(R.layout.restore_activity_contactlist);
mLayout = findViewById(R.id.contactlist_swipe_container);
mAdapter = new ContactListAdapter(getBaseContext(), mObjects);
mContactInfos = findViewById(R.id.contactinfos_layout);
ListView contactPhoneListView = findViewById(R.id.contact_phonelistView);
mContactPhoneListAdapter = new RecoveryPhoneNumberListViewAdapter(getBaseContext());
assert contactPhoneListView != null;
contactPhoneListView.setAdapter(mContactPhoneListAdapter);
mContactInfos.setVisibility(View.INVISIBLE);
initSpinner();
createAccountList();
}
private void createAccountList() {
final ProgressBar contactProgressBar = findViewById(R.id.contactlist_pgbar);
assert contactProgressBar != null;
String accountName = getIntent().getExtras().getString("account");
assert accountName != null;
Account[] myAccountList =
ContactListActivity.mAccountMgr.getAccountsByType(getString(R.string.account_type));
for (final Account element : myAccountList) {
if (element.name.equals(accountName)) {
// Load "contacts"
contactProgressBar.setVisibility(View.VISIBLE);
new ContactLoadTask(element, getBaseContext(), mAdapter, mObjects, mLayout,
contactProgressBar, mContactInfos).execute();
// Add refresh handler
mLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
mLayout.setRefreshing(true);
mContactInfos.setVisibility(View.INVISIBLE);
contactProgressBar.setVisibility(View.VISIBLE);
(new Handler()).post(new Runnable() {
@Override
public void run() {
mObjects.clear();
mAdapter.notifyDataSetChanged();
new ContactLoadTask(element, getBaseContext(), mAdapter, mObjects,
mLayout, contactProgressBar, mContactInfos).execute();
}
});
}
});
return;
}
}
}
private void initSpinner() {
final Spinner sp = findViewById(R.id.contact_spinner);
assert sp != null;
sp.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
mContactInfos.setVisibility(View.INVISIBLE);
mContactPhoneListAdapter.clear();
mFetchedContact = sp.getSelectedItem().toString();
fetchContact(mFetchedContact);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
// Nothing to do there
}
});
sp.setAdapter(mAdapter);
}
private void fetchContact(String name) {
if (!PermissionChecker.checkPermission(this, Manifest.permission.READ_CONTACTS,
REQUEST_CONTACTS)) {
return;
}
Cursor people = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI,
null, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " = ?",
new String[]{name}, null);
if (people == null) {
return;
}
people.moveToFirst();
Vector<String> r = new Vector<>();
if (people.getCount() == 0) {
return;
}
String contactId = people.getString(people.getColumnIndex(ContactsContract.Contacts._ID));
if ("1".equalsIgnoreCase(people.getString(people.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER)))) {
Cursor phones = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?",
new String[]{contactId}, null);
while ((phones != null) && phones.moveToNext()) {
r.add(phones.getString(phones.getColumnIndex(
ContactsContract.CommonDataKinds.Phone.NUMBER))
.replaceAll(" ", ""));
}
if (phones != null) {
phones.close();
}
}
Integer smsCount = 0;
// @TODO asynctask to load more datas
if (!r.isEmpty()) {
for (String pn: r) {
mContactPhoneListAdapter.add(pn);
}
} else {
mContactPhoneListAdapter.add(mFetchedContact);
}
mContactInfos.setVisibility(View.VISIBLE);
mContactPhoneListAdapter.notifyDataSetChanged();
}
/*
* Permissions
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
PermissionID requestCodeID = REQUEST_MAX;
if ((requestCode > 0) || (requestCode < REQUEST_MAX.ordinal())) {
requestCodeID = PermissionID.values()[requestCode];
}
switch (requestCodeID) {
case REQUEST_CONTACTS:
for (int grantResult : grantResults) {
Log.i("OcSMS", Integer.toString(grantResult));
}
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
fetchContact(mFetchedContact);
} else {
// Permission Denied
Toast.makeText(this, getString(R.string.err_cannot_read_contacts) + " " +
getString(R.string.please_fix_it), Toast.LENGTH_SHORT)
.show();
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
}

View File

@ -1,237 +0,0 @@
package fr.unix_experience.owncloud_sms.activities.remote_account;
/*
* Copyright (c) 2014-2016, 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.Manifest;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.provider.Telephony;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import fr.unix_experience.owncloud_sms.R;
import fr.unix_experience.owncloud_sms.engine.ASyncSMSRecovery;
import fr.unix_experience.owncloud_sms.engine.ConnectivityMonitor;
public class RestoreMessagesActivity extends AppCompatActivity {
Account _account = null;
String _defaultSmsApp;
private static final int REQUEST_DEFAULT_SMSAPP = 1;
boolean restoreInProgress = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_restore_messages);
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
assert getIntent().getExtras() != null;
String accountName = getIntent().getExtras().getString("account");
// accountName cannot be null, devel error
assert accountName != null;
AccountManager accountManager = AccountManager.get(getBaseContext());
Account[] accountList = accountManager.getAccountsByType(getString(R.string.account_type));
for (Account element : accountList) {
if (element.name.equals(accountName)) {
_account = element;
}
}
if (_account == null) {
throw new IllegalStateException(getString(R.string.err_didnt_find_account_restore));
}
initInterface();
Button fix_button = findViewById(R.id.button_fix_permissions);
final Button launch_restore = findViewById(R.id.button_launch_restore);
final ProgressBar pb = findViewById(R.id.progressbar_restore);
final RestoreMessagesActivity me = this;
fix_button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.KITKAT) {
notifyIncompatibleVersion();
return;
}
if (!new ConnectivityMonitor(me).isValid()) {
notifyNoConnectivity();
return;
}
Log.i(RestoreMessagesActivity.TAG, "Ask to change the default SMS app");
Intent intent = new Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT);
intent.putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME, getBaseContext().getPackageName());
startActivityForResult(intent, REQUEST_DEFAULT_SMSAPP);
}
});
launch_restore.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (!new ConnectivityMonitor(me).isValid()) {
notifyNoConnectivity();
return;
}
launch_restore.setVisibility(View.INVISIBLE);
pb.setVisibility(View.VISIBLE);
// Verify connectivity
Log.i(RestoreMessagesActivity.TAG, "Launching restore asynchronously");
restoreInProgress = true;
new ASyncSMSRecovery.SMSRecoveryTask(me, _account).execute();
}
});
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
boolean retval = true;
switch (item.getItemId()) {
case android.R.id.home:
finish();
break;
default:
retval = super.onOptionsItemSelected(item);
}
return retval;
}
private void initInterface() {
TextView tv_error = findViewById(R.id.tv_error_default_smsapp);
tv_error.setText(R.string.error_make_default_sms_app);
findViewById(R.id.tv_restore_finished).setVisibility(View.INVISIBLE);
findViewById(R.id.tv_progress_value).setVisibility(View.INVISIBLE);
Button fix_button = findViewById(R.id.button_fix_permissions);
Button launch_restore = findViewById(R.id.button_launch_restore);
ProgressBar pb = findViewById(R.id.progressbar_restore);
pb.setVisibility(View.INVISIBLE);
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.KITKAT) {
notifyIncompatibleVersion();
return;
}
_defaultSmsApp = Telephony.Sms.getDefaultSmsPackage(this);
if (!Telephony.Sms.getDefaultSmsPackage(this).equals(getPackageName())) {
_defaultSmsApp = Telephony.Sms.getDefaultSmsPackage(getBaseContext());
tv_error.setVisibility(View.VISIBLE);
fix_button.setVisibility(View.VISIBLE);
launch_restore.setVisibility(View.INVISIBLE);
} else {
tv_error.setVisibility(View.INVISIBLE);
fix_button.setVisibility(View.INVISIBLE);
launch_restore.setVisibility(View.VISIBLE);
}
}
private void errorNotification(int err) {
TextView tv = findViewById(R.id.tv_error_default_smsapp);
Button fix_button = findViewById(R.id.button_fix_permissions);
Button launch_restore = findViewById(R.id.button_launch_restore);
ProgressBar pb = findViewById(R.id.progressbar_restore);
tv.setText(err);
tv.setVisibility(View.VISIBLE);
fix_button.setVisibility(View.INVISIBLE);
launch_restore.setVisibility(View.INVISIBLE);
pb.setVisibility(View.INVISIBLE);
}
private void notifyIncompatibleVersion() {
errorNotification(R.string.err_kitkat_required);
}
private void notifyNoConnectivity() {
errorNotification(R.string.err_no_connection);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case RestoreMessagesActivity.REQUEST_DEFAULT_SMSAPP:
if (resultCode == Activity.RESULT_OK) {
TextView tv = findViewById(R.id.tv_error_default_smsapp);
Button fix_button = findViewById(R.id.button_fix_permissions);
Button launch_restore = findViewById(R.id.button_launch_restore);
tv.setVisibility(View.INVISIBLE);
fix_button.setVisibility(View.INVISIBLE);
launch_restore.setVisibility(View.VISIBLE);
}
break;
default:
break;
}
}
@Override
protected void onResume() {
super.onResume();
if (!new ConnectivityMonitor(this).isValid()) {
notifyNoConnectivity();
return;
}
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.KITKAT) {
notifyIncompatibleVersion();
return;
}
if (!restoreInProgress) {
initInterface();
}
}
public void onRestoreDone() {
findViewById(R.id.progressbar_restore).setVisibility(View.INVISIBLE);
findViewById(R.id.tv_restore_finished).setVisibility(View.VISIBLE);
Intent finalIntent = new Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT);
finalIntent.putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME, _defaultSmsApp);
startActivity(finalIntent);
restoreInProgress = false;
}
public void onProgressUpdate(Integer value) {
TextView tv_progress = findViewById(R.id.tv_progress_value);
if (tv_progress.getVisibility() == View.INVISIBLE) {
tv_progress.setVisibility(View.VISIBLE);
}
tv_progress.setText(value.toString() + " " + getString(R.string.x_messages_restored));
}
private static final String TAG = RestoreMessagesActivity.class.getSimpleName();
}

View File

@ -1,213 +0,0 @@
package fr.unix_experience.owncloud_sms.activities.virtual;
/**
* Copyright (c) 2013-2015, Loic Blot <loic.blot@unix-experience.fr>
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those
* of the authors and should not be interpreted as representing official policies,
* either expressed or implied, of the FreeBSD Project.
*/
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment;
import android.preference.PreferenceManager;
import android.util.Log;
import java.util.Vector;
public class VirtualSettingsActivity extends PreferenceActivity {
private static String TAG = VirtualSettingsActivity.class.getSimpleName();
protected static Context _context;
protected static int _prefsRessourceFile;
protected static Vector<BindObjectPref> _boolPrefs = new Vector<>();
protected static Vector<BindObjectPref> _stringPrefs = new Vector<>();
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
VirtualSettingsActivity._context = getBaseContext();
setupSimplePreferencesScreen();
}
/**
* Shows the simplified settings UI if the device configuration if the
* device configuration dictates that a simplified, single-pane UI should be
* shown.
*/
@SuppressWarnings("deprecation")
private void setupSimplePreferencesScreen() {
if (!VirtualSettingsActivity.isSimplePreferences(this)) {
return;
}
// In the simplified UI, fragments are not used at all and we instead
// use the older PreferenceActivity APIs.
addPreferencesFromResource(VirtualSettingsActivity._prefsRessourceFile);
bindPreferences();
}
/** {@inheritDoc} */
@Override
public boolean onIsMultiPane() {
return VirtualSettingsActivity.isXLargeTablet(this) && !VirtualSettingsActivity.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 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.
*/
protected static boolean isSimplePreferences(Context context) {
return (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB)
|| !VirtualSettingsActivity.isXLargeTablet(context);
}
/**
* 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 #bindPreferenceBooleanToValue
*/
public void bindPreferenceBooleanToValue(Preference preference, Boolean defValue) {
// Set the listener to watch for value changes.
preference
.setOnPreferenceChangeListener(_bindPreferenceListener);
// Trigger the listener immediately with the preference's
// current value.
_bindPreferenceListener.onPreferenceChange(
preference,
PreferenceManager.getDefaultSharedPreferences(
preference.getContext()).getBoolean(
preference.getKey(),
defValue
)
);
}
public void bindPreferenceStringToValue(Preference preference, String defValue) {
// Set the listener to watch for value changes.
preference
.setOnPreferenceChangeListener(_bindPreferenceListener);
// Trigger the listener immediately with the preference's
// current value.
_bindPreferenceListener.onPreferenceChange(
preference,
PreferenceManager.getDefaultSharedPreferences(
preference.getContext()).getString(
preference.getKey(),
defValue
)
);
}
/**
* 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(VirtualSettingsActivity._prefsRessourceFile);
VirtualSettingsActivity a = (VirtualSettingsActivity) getActivity();
a.bindPreferences();
}
}
public void bindPreferences() {
// 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.
for (BindObjectPref pref: VirtualSettingsActivity._stringPrefs) {
bindPreferenceStringToValue(findPreference(pref.name),
(String) pref.value);
}
for (BindObjectPref pref: VirtualSettingsActivity._boolPrefs) {
bindPreferenceBooleanToValue(findPreference(pref.name),
(Boolean) pref.value);
}
}
// The preference object, it's only a key value pair
protected class BindObjectPref {
public String name;
Object value;
public BindObjectPref(int resId, Object prefVal) {
name = getString(resId);
value = prefVal;
}
}
/**
* A preference value change listener that updates the preference's summary
* to reflect its new value.
*/
private final Preference.OnPreferenceChangeListener _bindPreferenceListener = new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object value) {
if (preference instanceof ListPreference) {
Log.i(TAG, "Changed list preference " + preference.toString() + " value " + value.toString());
handleListPreference(preference.getKey(), value.toString(), (ListPreference) preference);
} else if (preference instanceof CheckBoxPreference) {
Log.i(TAG, "Changed checkbox preference " + preference.toString() + " value " + value.toString());
handleCheckboxPreference(preference.getKey(), (Boolean) value);
} else {
// For all other preferences, set the summary to the value's
// simple string representation.
//preference.setSummary(boolValue);
}
return true;
}
};
protected void handleCheckboxPreference(String key, Boolean value) {}
protected void handleListPreference(String key, String value,
ListPreference preference) {}
}

View File

@ -1,63 +0,0 @@
package fr.unix_experience.owncloud_sms.adapters;
import android.accounts.Account;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import java.util.ArrayList;
public class AndroidAccountAdapter extends ArrayAdapter<Account> {
private final ArrayList<Account> _accounts;
private static int _itemLayout;
private static int _accountFieldId;
private final Activity _activity;
Class<?> _newActivityClass;
public AndroidAccountAdapter(Activity activity, int resource,
ArrayList<Account> objects, int itemLayout,
int accountFieldId, Class<?> newActivityClass) {
super(activity.getBaseContext(), resource, objects);
_accounts = objects;
AndroidAccountAdapter._itemLayout = itemLayout;
AndroidAccountAdapter._accountFieldId = accountFieldId;
_activity = activity;
_newActivityClass = newActivityClass;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(AndroidAccountAdapter._itemLayout, null);
}
final Account account = _accounts.get(position);
if (account != null) {
TextView label = v.findViewById(AndroidAccountAdapter._accountFieldId);
if (label != null) {
label.setText(account.name + " >");
v.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(_activity, _newActivityClass);
i.putExtra("account", account.name);
_activity.startActivity(i);
}
});
}
}
return v;
}
}

View File

@ -1,50 +0,0 @@
package fr.unix_experience.owncloud_sms.adapters;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import java.util.ArrayList;
import fr.unix_experience.owncloud_sms.R;
public class ContactListAdapter extends ArrayAdapter<String> {
private final ArrayList<String> _objects;
// Design
private final static int _itemLayout = R.layout.contact_list_item;
private final static int _fieldId = R.id.contactname;
public ContactListAdapter(Context context, ArrayList<String> objects) {
super(context, android.R.layout.simple_spinner_item, objects);
_objects = objects;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater inflater =
(LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(ContactListAdapter._itemLayout, null);
}
if (_objects.isEmpty()) {
return null;
}
String element = _objects.get(position);
if (element != null) {
TextView label = v.findViewById(ContactListAdapter._fieldId);
if (label != null) {
label.setText(element);
}
}
return v;
}
}

View File

@ -1,55 +0,0 @@
package fr.unix_experience.owncloud_sms.adapters;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import java.util.ArrayList;
import fr.unix_experience.owncloud_sms.R;
public class RecoveryPhoneNumberListViewAdapter extends ArrayAdapter<String> {
private static final String TAG = "RecPhoneNumberListVAdp";
private static int _fieldId = R.id.recovery_phone;
private static int _itemLayout = R.layout.recovery_phone_list_item;
private static int resource = android.R.layout.simple_list_item_2;
public RecoveryPhoneNumberListViewAdapter(Context context) {
super(context, resource, new ArrayList<String>());
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(RecoveryPhoneNumberListViewAdapter._itemLayout, null);
}
TextView label = v.findViewById(RecoveryPhoneNumberListViewAdapter._fieldId);
if (label != null) {
final String l = getItem(position).toString();
label.setText(getItem(position).toString());
v.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.i(TAG, "Clicked on phone " + l);
}
});
v.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
Log.i(TAG, "Long clicked on phone " + l);
return false;
}
});
}
return v;
}
}

View File

@ -1,98 +0,0 @@
package fr.unix_experience.owncloud_sms.broadcast_receivers;
/*
* Copyright (c) 2014-2015, 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.Manifest;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import java.util.concurrent.atomic.AtomicReference;
import fr.unix_experience.owncloud_sms.R;
import fr.unix_experience.owncloud_sms.engine.ASyncSMSSync;
import fr.unix_experience.owncloud_sms.engine.AndroidSmsFetcher;
import fr.unix_experience.owncloud_sms.engine.ConnectivityMonitor;
import fr.unix_experience.owncloud_sms.enums.PermissionID;
import fr.unix_experience.owncloud_sms.prefs.OCSMSSharedPrefs;
import fr.unix_experience.owncloud_sms.prefs.PermissionChecker;
import ncsmsgo.SmsBuffer;
public class ConnectivityChanged extends BroadcastReceiver implements ASyncSMSSync {
@Override
public void onReceive(Context context, Intent intent) {
// No account: abort
Account[] myAccountList = AccountManager.get(context).
getAccountsByType(context.getString(R.string.account_type));
if (myAccountList.length == 0) {
return;
}
ConnectivityMonitor cMon = new ConnectivityMonitor(context);
OCSMSSharedPrefs prefs = new OCSMSSharedPrefs(context);
if (!prefs.pushOnReceive()) {
Log.i(ConnectivityChanged.TAG,"ConnectivityChanges.onReceive: pushOnReceive is disabled");
return;
}
// If data is available and previous dataConnectionState was false, then we need to sync
if (cMon.isValid() && !ConnectivityChanged.dataConnectionAvailable) {
ConnectivityChanged.dataConnectionAvailable = true;
Log.i(ConnectivityChanged.TAG,"ConnectivityChanged.onReceive, data conn available");
if (!PermissionChecker.checkPermission(context, Manifest.permission.READ_SMS,
PermissionID.REQUEST_SMS)) {
return;
}
checkMessagesAndSend(context);
}
// No data available and previous dataConnectionState was true
else if (ConnectivityChanged.dataConnectionAvailable && !cMon.isValid()) {
ConnectivityChanged.dataConnectionAvailable = false;
Log.i(ConnectivityChanged.TAG,"ConnectivityChanges.onReceive: data conn is off");
}
}
private void checkMessagesAndSend(Context context) {
// Get last message synced from preferences
Long lastMessageSynced = (new OCSMSSharedPrefs(context)).getLastMessageDate();
Log.i(ConnectivityChanged.TAG,"Synced Last:" + lastMessageSynced);
// Now fetch messages since last stored date
SmsBuffer smsBuffer = new SmsBuffer();
new AndroidSmsFetcher(context).bufferMessagesSinceDate(smsBuffer, lastMessageSynced);
AtomicReference<ConnectivityMonitor> cMon = new AtomicReference<>(new ConnectivityMonitor(context));
// Synchronize if network is valid and there are SMS
if (cMon.get().isValid() && !smsBuffer.empty()) {
new SyncTask(context, smsBuffer).execute();
}
}
private static boolean dataConnectionAvailable = false;
private static final String TAG = ConnectivityChanged.class.getSimpleName();
}

View File

@ -1,15 +0,0 @@
package fr.unix_experience.owncloud_sms.defines;
public class DefaultPrefs {
public final static Integer syncInterval = 15;
public final static Integer minimumCharsForSync = 0;
public final static Boolean pushOnReceive = true;
public final static Boolean showSyncNotifications = true;
public final static Boolean syncWifi = true;
public final static Boolean sync2G = true;
public final static Boolean syncGPRS = true;
public final static Boolean sync3G = true;
public final static Boolean sync4G = true;
public final static Boolean syncOthers = true;
}

View File

@ -1,153 +0,0 @@
package fr.unix_experience.owncloud_sms.engine;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.os.AsyncTask;
import android.provider.ContactsContract;
import android.support.v4.widget.SwipeRefreshLayout;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import java.util.ArrayList;
import java.util.Collections;
import fr.unix_experience.owncloud_sms.R;
import fr.unix_experience.owncloud_sms.adapters.ContactListAdapter;
import fr.unix_experience.owncloud_sms.exceptions.OCSyncException;
import ncsmsgo.SmsPhoneListResponse;
public interface ASyncContactLoad {
class ContactLoadTask extends AsyncTask<Void, Void, Boolean> {
private static AccountManager _accountMgr = null;
private static Account _account;
private final Context _context;
private final ContactListAdapter _adapter;
private final ArrayList<String> _objects;
private final SwipeRefreshLayout _layout;
private final ProgressBar _pg;
private final LinearLayout _contactLayout;
public ContactLoadTask(Account account, Context context,
ContactListAdapter adapter, ArrayList<String> objects, SwipeRefreshLayout layout,
ProgressBar pg, LinearLayout sp) {
if (ContactLoadTask._accountMgr == null) {
ContactLoadTask._accountMgr = AccountManager.get(context);
}
ContactLoadTask._account = account;
_context = context;
_adapter = adapter;
_objects = objects;
_layout = layout;
_pg = pg;
_contactLayout = sp;
}
@Override
protected Boolean doInBackground(Void... params) {
OCSMSOwnCloudClient _client = null;
try {
_client = new OCSMSOwnCloudClient(_context, ContactLoadTask._account);
}
catch (IllegalStateException e) {
return false;
}
// Remove all objects, due to refreshing handling
_objects.clear();
try {
if (_client.getServerAPIVersion() < 2) {
_objects.add(_context.getString(R.string.err_proto_v2));
return false;
}
ArrayList<String> serverPhoneList = new ArrayList<>();
SmsPhoneListResponse splr = _client.getServerPhoneNumbers();
if (splr == null) {
_objects.add(_context.getString(R.string.err_fetch_phonelist));
return false;
}
String phoneNumber;
while (!(phoneNumber = splr.getNextEntry()).equals("")) {
serverPhoneList.add(phoneNumber);
}
// Read all contacts
readContacts(serverPhoneList);
_objects.addAll(serverPhoneList);
// Sort phone numbers
Collections.sort(_objects);
} catch (OCSyncException e) {
_objects.add(_context.getString(e.getErrorId()));
return false;
}
return true;
}
private void readContacts(ArrayList<String> serverPhoneList) {
ContentResolver cr = _context.getContentResolver();
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI,
null, null, null, null);
if (cur == null) {
return;
}
if (cur.getCount() == 0) {
cur.close();
return;
}
String id, name;
while (cur.moveToNext()) {
id = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));
name = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
if (Integer.parseInt(cur.getString(
cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0) {
// Fetch all phone numbers
Cursor pCur = cr.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?",
new String[]{id}, null);
while ((pCur != null) && pCur.moveToNext()) {
String phoneNo = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER))
.replaceAll(" ", "");
if (serverPhoneList.contains(phoneNo)) {
if (!_objects.contains(name)) {
_objects.add(name);
}
serverPhoneList.remove(phoneNo);
}
}
if (pCur != null) {
pCur.close();
}
}
}
cur.close();
}
protected void onPostExecute(Boolean success) {
_adapter.notifyDataSetChanged();
_layout.setRefreshing(false);
if (_pg != null) {
_pg.setVisibility(View.INVISIBLE);
}
if (_contactLayout != null) {
_contactLayout.setVisibility(View.VISIBLE);
}
}
}
String TAG = ASyncContactLoad.class.getSimpleName();
}

Some files were not shown because too many files have changed in this diff Show More