diff options
| author | Menny Even Danan <menny@evendanan.net> | 2016-02-25 23:55:35 +0000 |
|---|---|---|
| committer | Menny Even Danan <menny@evendanan.net> | 2016-02-25 23:55:35 +0000 |
| commit | 92cd901da558d31409bfec60b9c16daedad4a248 (patch) | |
| tree | 23b3ebb0e8d73b5c1c112359d896de67238db6b1 /src/main/java/com/anysoftkeyboard | |
| parent | 0f1bf1c2b7ee79f3fa5dfb282958a97c8f2128f5 (diff) | |
| download | AnySoftKeyboard-92cd901da558d31409bfec60b9c16daedad4a248.tar.gz AnySoftKeyboard-92cd901da558d31409bfec60b9c16daedad4a248.tar.bz2 | |
adding Marshmallow permissions support. #470
Diffstat (limited to 'src/main/java/com/anysoftkeyboard')
5 files changed, 102 insertions, 10 deletions
diff --git a/src/main/java/com/anysoftkeyboard/PermissionsRequestCodes.java b/src/main/java/com/anysoftkeyboard/PermissionsRequestCodes.java new file mode 100644 index 000000000..c0f23bad2 --- /dev/null +++ b/src/main/java/com/anysoftkeyboard/PermissionsRequestCodes.java @@ -0,0 +1,12 @@ +package com.anysoftkeyboard; + +public enum PermissionsRequestCodes { + CONTACTS, + STORAGE_READ, + STORAGE_WRITE, + LAST_ENTRY; + + public int getRequestCode() { + return ordinal() + 1; + } +} diff --git a/src/main/java/com/anysoftkeyboard/dictionaries/Suggest.java b/src/main/java/com/anysoftkeyboard/dictionaries/Suggest.java index 4d053c6d5..64bd1b04c 100644 --- a/src/main/java/com/anysoftkeyboard/dictionaries/Suggest.java +++ b/src/main/java/com/anysoftkeyboard/dictionaries/Suggest.java @@ -86,6 +86,17 @@ public class Suggest implements Dictionary.WordCallback { private int mCommonalityMaxLengthDiff = 1; private int mCommonalityMaxDistance = 1; + private final DictionaryASyncLoader.Listener mContactsDictionaryListener = new DictionaryASyncLoader.Listener() { + @Override + public void onDictionaryLoadingDone(Dictionary dictionary) {} + + @Override + public void onDictionaryLoadingFailed(Dictionary dictionary, Exception exception) { + if (dictionary == mContactsDictionary) { + mContactsDictionary = null;//resetting it + } + } + }; public Suggest(Context context) { mDictionaryFactory = createDictionaryFactory(); @@ -184,7 +195,7 @@ public class Suggest implements Dictionary.WordCallback { // config says it should be on, but I have none. mContactsDictionary = mDictionaryFactory.createContactsDictionary(context); if (mContactsDictionary != null) {//not all devices has contacts-dictionary - DictionaryASyncLoader loader = new DictionaryASyncLoader(null); + DictionaryASyncLoader loader = new DictionaryASyncLoader(mContactsDictionaryListener); loader.execute(mContactsDictionary); } } diff --git a/src/main/java/com/anysoftkeyboard/dictionaries/content/ContactsDictionary.java b/src/main/java/com/anysoftkeyboard/dictionaries/content/ContactsDictionary.java index d129c3cf1..7a32022a9 100644 --- a/src/main/java/com/anysoftkeyboard/dictionaries/content/ContactsDictionary.java +++ b/src/main/java/com/anysoftkeyboard/dictionaries/content/ContactsDictionary.java @@ -16,15 +16,26 @@ package com.anysoftkeyboard.dictionaries.content; +import android.Manifest; import android.annotation.TargetApi; +import android.app.PendingIntent; import android.content.ContentResolver; import android.content.Context; +import android.content.Intent; import android.database.ContentObserver; import android.database.Cursor; +import android.database.MatrixCursor; import android.provider.ContactsContract.Contacts; +import android.support.v4.app.NotificationCompat; +import android.support.v4.app.NotificationManagerCompat; +import com.anysoftkeyboard.PermissionsRequestCodes; import com.anysoftkeyboard.base.dictionaries.WordsCursor; import com.anysoftkeyboard.dictionaries.BTreeDictionary; +import com.anysoftkeyboard.ui.settings.MainSettingsActivity; +import com.menny.android.anysoftkeyboard.R; + +import net.evendanan.chauffeur.lib.permissions.PermissionsFragmentChauffeurActivity; @TargetApi(7) public class ContactsDictionary extends BTreeDictionary { @@ -75,10 +86,34 @@ public class ContactsDictionary extends BTreeDictionary { @Override public WordsCursor getWordsCursor() { - Cursor cursor = mContext.getContentResolver().query(Contacts.CONTENT_URI, - PROJECTION, Contacts.IN_VISIBLE_GROUP + "=?", - new String[]{"1"}, null); - return new ContactsWordsCursor(cursor); + //we required Contacts permission + Intent contactsRequired = PermissionsFragmentChauffeurActivity.createIntentToPermissionsRequest(mContext, MainSettingsActivity.class, PermissionsRequestCodes.CONTACTS.getRequestCode(), Manifest.permission.READ_CONTACTS); + if (contactsRequired != null) { + //we are running OUTSIDE an Activity + contactsRequired.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + //showing a notification, so the user's flow will not be interrupted. + showNotificationWithIntent(contactsRequired); + //and failing. So it will try to read contacts again + throw new RuntimeException("We do not have permission to read contacts!"); + } else { + Cursor cursor = mContext.getContentResolver().query(Contacts.CONTENT_URI, + PROJECTION, Contacts.IN_VISIBLE_GROUP + "=?", + new String[]{"1"}, null); + return new ContactsWordsCursor(cursor); + } + } + + private void showNotificationWithIntent(Intent contactsRequired) { + final int requestId = PermissionsRequestCodes.CONTACTS.getRequestCode(); + PendingIntent pendingIntent = PendingIntent.getActivity(mContext, requestId, contactsRequired, 0); + NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext); + builder.setTicker(mContext.getString(R.string.notification_read_contacts_ticker)); + builder.setSmallIcon(R.drawable.ic_notification_contacts_permission_required); + builder.setContentIntent(pendingIntent); + builder.setContentTitle(mContext.getString(R.string.notification_read_contacts_title)); + builder.setContentText(mContext.getString(R.string.notification_read_contacts_text)); + builder.setAutoCancel(true); + NotificationManagerCompat.from(mContext).notify(requestId, builder.build()); } @Override @@ -133,4 +168,10 @@ public class ContactsDictionary extends BTreeDictionary { protected void closeStorage() { /*nothing to close here*/ } + + private static class EmptyCursor extends MatrixCursor { + public EmptyCursor() { + super(PROJECTION, 0); + } + } } diff --git a/src/main/java/com/anysoftkeyboard/ui/settings/MainSettingsActivity.java b/src/main/java/com/anysoftkeyboard/ui/settings/MainSettingsActivity.java index 61f5357a0..d3e773fec 100644 --- a/src/main/java/com/anysoftkeyboard/ui/settings/MainSettingsActivity.java +++ b/src/main/java/com/anysoftkeyboard/ui/settings/MainSettingsActivity.java @@ -37,11 +37,11 @@ import com.anysoftkeyboard.theme.KeyboardThemeFactory; import com.menny.android.anysoftkeyboard.AnyApplication; import com.menny.android.anysoftkeyboard.R; -import net.evendanan.chauffeur.lib.FragmentChauffeurActivity; import net.evendanan.chauffeur.lib.experiences.TransitionExperiences; +import net.evendanan.chauffeur.lib.permissions.PermissionsFragmentChauffeurActivity; import net.evendanan.pushingpixels.EdgeEffectHacker; -public class MainSettingsActivity extends FragmentChauffeurActivity { +public class MainSettingsActivity extends PermissionsFragmentChauffeurActivity { private DrawerLayout mDrawerRootLayout; private ActionBarDrawerToggle mDrawerToggle; diff --git a/src/main/java/com/anysoftkeyboard/ui/settings/wordseditor/UserDictionaryEditorFragment.java b/src/main/java/com/anysoftkeyboard/ui/settings/wordseditor/UserDictionaryEditorFragment.java index 0c486f96b..0868b4082 100644 --- a/src/main/java/com/anysoftkeyboard/ui/settings/wordseditor/UserDictionaryEditorFragment.java +++ b/src/main/java/com/anysoftkeyboard/ui/settings/wordseditor/UserDictionaryEditorFragment.java @@ -16,14 +16,17 @@ package com.anysoftkeyboard.ui.settings.wordseditor; +import android.Manifest; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; +import android.content.pm.PackageManager; import android.database.Cursor; import android.graphics.Rect; import android.os.Bundle; +import android.support.annotation.NonNull; import android.support.annotation.VisibleForTesting; import android.support.v4.app.Fragment; import android.support.v7.app.ActionBar; @@ -42,6 +45,7 @@ import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ArrayAdapter; import android.widget.Spinner; +import com.anysoftkeyboard.PermissionsRequestCodes; import com.anysoftkeyboard.base.dictionaries.EditableDictionary; import com.anysoftkeyboard.base.dictionaries.WordsCursor; import com.anysoftkeyboard.dictionaries.UserDictionary; @@ -139,21 +143,36 @@ public class UserDictionaryEditorFragment extends Fragment @Override public boolean onOptionsItemSelected(MenuItem item) { + MainSettingsActivity mainSettingsActivity = (MainSettingsActivity) getActivity(); + if (mainSettingsActivity == null) return super.onOptionsItemSelected(item); switch (item.getItemId()) { case R.id.add_user_word: createEmptyItemForAdd(); return true; case R.id.backup_words: - new BackupUserWordsAsyncTask(UserDictionaryEditorFragment.this, ASK_USER_WORDS_SDCARD_FILENAME).execute(); + //we required Storage permission + if (!mainSettingsActivity.startPermissionsRequestFromFragment(this, PermissionsRequestCodes.STORAGE_WRITE.getRequestCode(), Manifest.permission.WRITE_EXTERNAL_STORAGE)) { + backupToStorage(); + } return true; case R.id.restore_words: - new RestoreUserWordsAsyncTask(UserDictionaryEditorFragment.this, ASK_USER_WORDS_SDCARD_FILENAME).execute(); + if (!mainSettingsActivity.startPermissionsRequestFromFragment(this, PermissionsRequestCodes.STORAGE_READ.getRequestCode(), Manifest.permission.WRITE_EXTERNAL_STORAGE)) { + restoreFromStorage(); + } return true; default: return super.onOptionsItemSelected(item); } } + private void restoreFromStorage() { + new RestoreUserWordsAsyncTask(UserDictionaryEditorFragment.this, ASK_USER_WORDS_SDCARD_FILENAME).execute(); + } + + private void backupToStorage() { + new BackupUserWordsAsyncTask(UserDictionaryEditorFragment.this, ASK_USER_WORDS_SDCARD_FILENAME).execute(); + } + private void createEmptyItemForAdd() { EditorWordsAdapter adapter = (EditorWordsAdapter) mWordsRecyclerView.getAdapter(); if (adapter == null || !isResumed()) return; @@ -167,7 +186,6 @@ public class UserDictionaryEditorFragment extends Fragment fillLanguagesSpinner(); } - @Override public void onDestroy() { FragmentChauffeurActivity activity = (FragmentChauffeurActivity) getActivity(); @@ -190,6 +208,16 @@ public class UserDictionaryEditorFragment extends Fragment mCurrentDictionary = null; } + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == PermissionsRequestCodes.STORAGE_WRITE.getRequestCode() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + backupToStorage(); + } else if (requestCode == PermissionsRequestCodes.STORAGE_READ.getRequestCode() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + restoreFromStorage(); + } + } + void fillLanguagesSpinner() { new UserWordsEditorAsyncTask(this, true) { private ArrayAdapter<DictionaryLocale> mAdapter; |
