aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/com/anysoftkeyboard
diff options
context:
space:
mode:
authorMenny Even Danan <menny@evendanan.net>2016-02-25 23:55:35 +0000
committerMenny Even Danan <menny@evendanan.net>2016-02-25 23:55:35 +0000
commit92cd901da558d31409bfec60b9c16daedad4a248 (patch)
tree23b3ebb0e8d73b5c1c112359d896de67238db6b1 /src/main/java/com/anysoftkeyboard
parent0f1bf1c2b7ee79f3fa5dfb282958a97c8f2128f5 (diff)
downloadAnySoftKeyboard-92cd901da558d31409bfec60b9c16daedad4a248.tar.gz
AnySoftKeyboard-92cd901da558d31409bfec60b9c16daedad4a248.tar.bz2
adding Marshmallow permissions support. #470
Diffstat (limited to 'src/main/java/com/anysoftkeyboard')
-rw-r--r--src/main/java/com/anysoftkeyboard/PermissionsRequestCodes.java12
-rw-r--r--src/main/java/com/anysoftkeyboard/dictionaries/Suggest.java13
-rw-r--r--src/main/java/com/anysoftkeyboard/dictionaries/content/ContactsDictionary.java49
-rw-r--r--src/main/java/com/anysoftkeyboard/ui/settings/MainSettingsActivity.java4
-rw-r--r--src/main/java/com/anysoftkeyboard/ui/settings/wordseditor/UserDictionaryEditorFragment.java34
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;