From 675940918859ac4c89a1dc3aa4bd7b292713fc57 Mon Sep 17 00:00:00 2001 From: Loic Blot Date: Fri, 8 Apr 2016 08:54:51 +0200 Subject: [PATCH] 0.21.2: Android 6.0 permissions fixes --- src/main/AndroidManifest.xml | 4 +- .../owncloud_sms/activities/MainActivity.java | 64 +++++- .../remote_account/ContactListActivity.java | 215 +++++++++++------- .../ConnectivityChanged.java | 10 +- .../enums/OCSMSNotificationType.java | 1 + .../owncloud_sms/observers/SmsObserver.java | 8 + src/main/res/menu/activity_main_drawer.xml | 4 + src/main/res/values-en/strings.xml | 8 + src/main/res/values-es/strings.xml | 1 + src/main/res/values-fr/strings.xml | 8 + src/main/res/values/strings.xml | 8 + 11 files changed, 238 insertions(+), 93 deletions(-) diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index 787ec33..609aed3 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -1,8 +1,8 @@ + android:versionCode="37" + android:versionName="0.21.2"> + * Copyright (c) 2014-2016, Loic Blot * All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -25,11 +25,14 @@ package fr.unix_experience.owncloud_sms.activities; * 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; @@ -46,7 +49,12 @@ import fr.unix_experience.owncloud_sms.engine.ASyncSMSSync.SyncTask; import fr.unix_experience.owncloud_sms.engine.ConnectivityMonitor; import fr.unix_experience.owncloud_sms.engine.SmsFetcher; import fr.unix_experience.owncloud_sms.enums.OCSMSNotificationType; +import fr.unix_experience.owncloud_sms.enums.PermissionID; import fr.unix_experience.owncloud_sms.notifications.OCSMSNotificationUI; +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{ @@ -54,8 +62,8 @@ public class MainActivity extends AppCompatActivity private static ConnectivityMonitor mConnectivityMonitor = null; @Override protected void onCreate(Bundle savedInstanceState) { - if (mConnectivityMonitor == null) { - mConnectivityMonitor = new ConnectivityMonitor(getApplicationContext()); + if (MainActivity.mConnectivityMonitor == null) { + MainActivity.mConnectivityMonitor = new ConnectivityMonitor(getApplicationContext()); } super.onCreate(savedInstanceState); @@ -88,11 +96,12 @@ public class MainActivity extends AppCompatActivity boolean res = true; switch (id) { - case R.id.nav_sync: res = syncAllMessages(); break; + 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; } DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); drawer.closeDrawer(GravityCompat.START); @@ -109,10 +118,15 @@ public class MainActivity extends AppCompatActivity return true; } - private boolean syncAllMessages () { + public void syncAllMessages () { + if (!PermissionChecker.checkPermission(this, Manifest.permission.READ_SMS, + REQUEST_SMS)) { + return; + } + Context ctx = getApplicationContext(); - if (mConnectivityMonitor.isValid()) { + if (MainActivity.mConnectivityMonitor.isValid()) { // Now fetch messages since last stored date JSONArray smsList = new JSONArray(); new SmsFetcher(ctx).bufferMessagesSinceDate(smsList, (long) 0); @@ -126,7 +140,6 @@ public class MainActivity extends AppCompatActivity else { Toast.makeText(ctx, ctx.getString(R.string.err_sync_no_connection_available), Toast.LENGTH_SHORT).show(); } - return true; } private boolean openMyAccounts () { @@ -145,4 +158,41 @@ public class MainActivity extends AppCompatActivity 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; + } + + /* + * 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); + } + } } diff --git a/src/main/java/fr/unix_experience/owncloud_sms/activities/remote_account/ContactListActivity.java b/src/main/java/fr/unix_experience/owncloud_sms/activities/remote_account/ContactListActivity.java index 15a4d61..450f537 100644 --- a/src/main/java/fr/unix_experience/owncloud_sms/activities/remote_account/ContactListActivity.java +++ b/src/main/java/fr/unix_experience/owncloud_sms/activities/remote_account/ContactListActivity.java @@ -1,19 +1,24 @@ 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; @@ -22,13 +27,21 @@ 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 _accountMgr; - ContactListAdapter adapter; - SwipeRefreshLayout _layout; - ArrayList objects; + static AccountManager mAccountMgr; + ContactListAdapter mAdapter = null; + SwipeRefreshLayout mLayout = null; + LinearLayout mContactInfos = null; + ArrayList mObjects; + String mFetchedContact; + RecoveryPhoneNumberListViewAdapter mContactPhoneListAdapter = null; @Override protected void onCreate(Bundle savedInstanceState) { @@ -41,49 +54,35 @@ public class ContactListActivity extends AppCompatActivity implements ASyncConta // accountName cannot be null, devel error assert accountName != null; - ContactListActivity._accountMgr = AccountManager.get(getBaseContext()); + ContactListActivity.mAccountMgr = AccountManager.get(getBaseContext()); Account[] myAccountList = - ContactListActivity._accountMgr.getAccountsByType(getString(R.string.account_type)); + ContactListActivity.mAccountMgr.getAccountsByType(getString(R.string.account_type)); // Init view - objects = new ArrayList<>(); + mObjects = new ArrayList<>(); setContentView(R.layout.restore_activity_contactlist); - _layout = (SwipeRefreshLayout) findViewById(R.id.contactlist_swipe_container); + mLayout = (SwipeRefreshLayout) findViewById(R.id.contactlist_swipe_container); - adapter = new ContactListAdapter(getBaseContext(), objects); + mAdapter = new ContactListAdapter(getBaseContext(), mObjects); final Spinner sp = (Spinner) findViewById(R.id.contact_spinner); - final LinearLayout contactInfos = (LinearLayout) findViewById(R.id.contactinfos_layout); + mContactInfos = (LinearLayout) findViewById(R.id.contactinfos_layout); final ProgressBar contactProgressBar = (ProgressBar) findViewById(R.id.contactlist_pgbar); final ListView contactPhoneListView = (ListView) findViewById(R.id.contact_phonelistView); - final RecoveryPhoneNumberListViewAdapter contactPhoneListAdapter = - new RecoveryPhoneNumberListViewAdapter(getBaseContext()); - contactPhoneListView.setAdapter(contactPhoneListAdapter); + mContactPhoneListAdapter = new RecoveryPhoneNumberListViewAdapter(getBaseContext()); + contactPhoneListView.setAdapter(mContactPhoneListAdapter); - contactInfos.setVisibility(View.INVISIBLE); + mContactInfos.setVisibility(View.INVISIBLE); sp.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView parent, View view, int position, long id) { - contactInfos.setVisibility(View.INVISIBLE); - contactPhoneListAdapter.clear(); + mContactInfos.setVisibility(View.INVISIBLE); + mContactPhoneListAdapter.clear(); - String contactName = sp.getSelectedItem().toString(); - Vector phoneList = fetchContact(contactName); - Integer smsCount = 0; - // @TODO asynctask to load more datas - - if (!phoneList.isEmpty()) { - for (String pn: phoneList) { - contactPhoneListAdapter.add(pn); - } - } else { - contactPhoneListAdapter.add(contactName); - } - - contactInfos.setVisibility(View.VISIBLE); - contactPhoneListAdapter.notifyDataSetChanged(); + mFetchedContact = sp.getSelectedItem().toString(); + fetchContact(mFetchedContact); } @Override @@ -91,69 +90,119 @@ public class ContactListActivity extends AppCompatActivity implements ASyncConta // Nothing to do there } - private Vector fetchContact(String name) { - Cursor people = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, - null, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " = ?", - new String[]{name}, null); - if (people == null) { - return new Vector<>(); - } - people.moveToFirst(); - - Vector r = new Vector<>(); - if (people.getCount() == 0) { - return r; - } - - 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(); - } - } - return r; - } }); - sp.setAdapter(adapter); + sp.setAdapter(mAdapter); for (final Account element : myAccountList) { if (element.name.equals(accountName)) { // Load "contacts" contactProgressBar.setVisibility(View.VISIBLE); - new ContactLoadTask(element, getBaseContext(), adapter, objects, _layout, contactProgressBar, contactInfos).execute(); + new ContactLoadTask(element, getBaseContext(), mAdapter, mObjects, mLayout, contactProgressBar, mContactInfos).execute(); // Add refresh handler - _layout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { - @Override - public void onRefresh() { - _layout.setRefreshing(true); - contactInfos.setVisibility(View.INVISIBLE); - contactProgressBar.setVisibility(View.VISIBLE); - (new Handler()).post(new Runnable() { - @Override - public void run() { - objects.clear(); - adapter.notifyDataSetChanged(); - new ContactLoadTask(element, getBaseContext(), adapter, objects, _layout, contactProgressBar, contactInfos).execute(); - } - }); - } - }); + 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 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 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.d("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); + } + } } diff --git a/src/main/java/fr/unix_experience/owncloud_sms/broadcast_receivers/ConnectivityChanged.java b/src/main/java/fr/unix_experience/owncloud_sms/broadcast_receivers/ConnectivityChanged.java index ec7e1b1..abd53e1 100644 --- a/src/main/java/fr/unix_experience/owncloud_sms/broadcast_receivers/ConnectivityChanged.java +++ b/src/main/java/fr/unix_experience/owncloud_sms/broadcast_receivers/ConnectivityChanged.java @@ -17,6 +17,7 @@ package fr.unix_experience.owncloud_sms.broadcast_receivers; * along with this program. If not, see . */ +import android.Manifest; import android.accounts.Account; import android.accounts.AccountManager; import android.content.BroadcastReceiver; @@ -32,7 +33,9 @@ import fr.unix_experience.owncloud_sms.R; import fr.unix_experience.owncloud_sms.engine.ASyncSMSSync; import fr.unix_experience.owncloud_sms.engine.ConnectivityMonitor; import fr.unix_experience.owncloud_sms.engine.SmsFetcher; +import fr.unix_experience.owncloud_sms.enums.PermissionID; import fr.unix_experience.owncloud_sms.prefs.OCSMSSharedPrefs; +import fr.unix_experience.owncloud_sms.prefs.PermissionChecker; public class ConnectivityChanged extends BroadcastReceiver implements ASyncSMSSync { @@ -58,6 +61,12 @@ public class ConnectivityChanged extends BroadcastReceiver implements ASyncSMSSy if (cMon.isValid() && !ConnectivityChanged.dataConnectionAvailable) { ConnectivityChanged.dataConnectionAvailable = true; Log.d(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 @@ -68,7 +77,6 @@ public class ConnectivityChanged extends BroadcastReceiver implements ASyncSMSSy } private void checkMessagesAndSend(Context context) { - // Get last message synced from preferences Long lastMessageSynced = (new OCSMSSharedPrefs(context)).getLastMessageDate(); Log.d(ConnectivityChanged.TAG,"Synced Last:" + lastMessageSynced); diff --git a/src/main/java/fr/unix_experience/owncloud_sms/enums/OCSMSNotificationType.java b/src/main/java/fr/unix_experience/owncloud_sms/enums/OCSMSNotificationType.java index bf9be53..096711c 100644 --- a/src/main/java/fr/unix_experience/owncloud_sms/enums/OCSMSNotificationType.java +++ b/src/main/java/fr/unix_experience/owncloud_sms/enums/OCSMSNotificationType.java @@ -21,4 +21,5 @@ public enum OCSMSNotificationType { SYNC, SYNC_FAILED, DEBUG, + PERMISSION, } diff --git a/src/main/java/fr/unix_experience/owncloud_sms/observers/SmsObserver.java b/src/main/java/fr/unix_experience/owncloud_sms/observers/SmsObserver.java index b612b12..fd25b68 100644 --- a/src/main/java/fr/unix_experience/owncloud_sms/observers/SmsObserver.java +++ b/src/main/java/fr/unix_experience/owncloud_sms/observers/SmsObserver.java @@ -17,6 +17,7 @@ package fr.unix_experience.owncloud_sms.observers; * along with this program. If not, see . */ +import android.Manifest; import android.accounts.Account; import android.accounts.AccountManager; import android.content.Context; @@ -32,6 +33,8 @@ import fr.unix_experience.owncloud_sms.engine.ConnectivityMonitor; 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 fr.unix_experience.owncloud_sms.enums.PermissionID; +import fr.unix_experience.owncloud_sms.prefs.PermissionChecker; public class SmsObserver extends ContentObserver implements ASyncSMSSync { @@ -41,6 +44,11 @@ public class SmsObserver extends ContentObserver implements ASyncSMSSync { } public void onChange(boolean selfChange) { + if (!PermissionChecker.checkPermission(_context, Manifest.permission.READ_SMS, + PermissionID.REQUEST_SMS)) { + return; + } + super.onChange(selfChange); Log.d(SmsObserver.TAG, "onChange SmsObserver"); diff --git a/src/main/res/menu/activity_main_drawer.xml b/src/main/res/menu/activity_main_drawer.xml index ecd9250..025eb66 100644 --- a/src/main/res/menu/activity_main_drawer.xml +++ b/src/main/res/menu/activity_main_drawer.xml @@ -18,6 +18,10 @@ android:id="@+id/nav_manage" android:icon="@drawable/ic_menu_manage" android:title="@string/action_settings"/> + diff --git a/src/main/res/values-en/strings.xml b/src/main/res/values-en/strings.xml index 5926e4a..62f5328 100644 --- a/src/main/res/values-en/strings.xml +++ b/src/main/res/values-en/strings.xml @@ -160,5 +160,13 @@ Communicate My accounts Swipe from left to right to access to action menu. + Cancel + Understood + Permissions required + Some permissions are missing to perform the sync process. Please fix it in app settings + Please fix it. + We cannot read your contacts. + We cannot read your SMS. + App Infos and permissions diff --git a/src/main/res/values-es/strings.xml b/src/main/res/values-es/strings.xml index 2654b16..82b15d1 100644 --- a/src/main/res/values-es/strings.xml +++ b/src/main/res/values-es/strings.xml @@ -91,4 +91,5 @@ Proceso de sincronización Sincronización en progreso... Error Fatal ! + diff --git a/src/main/res/values-fr/strings.xml b/src/main/res/values-fr/strings.xml index 1a64629..fdd22bc 100644 --- a/src/main/res/values-fr/strings.xml +++ b/src/main/res/values-fr/strings.xml @@ -145,4 +145,12 @@ Parlez de nous Mes comptes Glissez votre doigt de gauche à droite pour afficher le menu. + Annuler + J\'ai compris + Permissions requises + Certaines permissions essentielles sont manquantes, merci de les corriger dans les paramètres de l\'application. + Merci de bien vouloir le corriger. + Nous ne pouvons lire vos contacts. + Nous ne pouvons pas lire vos SMS. + Infos et permissions diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 47b89ba..4dc692d 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -195,4 +195,12 @@ Close navigation drawer My accounts Swipe from left to right to access to action menu. + Cancel + Understood + Permissions required + Some permissions are missing to perform the sync process. Please fix it in app settings + Please fix it. + We cannot read your contacts. + We cannot read your SMS. + App Infos and permissions