Loading app/core/src/main/java/com/fsck/k9/helper/Contacts.java +23 −6 Original line number Original line Diff line number Diff line package com.fsck.k9.helper; package com.fsck.k9.helper; import android.Manifest; import android.content.ContentResolver; import android.content.ContentResolver; import android.content.Context; import android.content.Context; import android.content.Intent; import android.content.Intent; import android.content.pm.PackageManager; import android.database.AbstractCursor; import android.database.Cursor; import android.database.Cursor; import android.net.Uri; import android.net.Uri; import android.provider.ContactsContract; import android.provider.ContactsContract; import timber.log.Timber; import timber.log.Timber; import android.provider.ContactsContract.CommonDataKinds.Photo; import android.provider.ContactsContract.CommonDataKinds.Photo; import android.support.v4.content.ContextCompat; import com.fsck.k9.mail.Address; import com.fsck.k9.mail.Address; Loading Loading @@ -263,6 +267,14 @@ public class Contacts { } } } } private boolean hasContactPermission() { boolean canRead = ContextCompat.checkSelfPermission(mContext, Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED; boolean canWrite = ContextCompat.checkSelfPermission(mContext, Manifest.permission.WRITE_CONTACTS) == PackageManager.PERMISSION_GRANTED; return canRead && canWrite; } /** /** * Return a {@link Cursor} instance that can be used to fetch information * Return a {@link Cursor} instance that can be used to fetch information * about the contact with the given email address. * about the contact with the given email address. Loading @@ -273,12 +285,17 @@ public class Contacts { */ */ private Cursor getContactByAddress(final String address) { private Cursor getContactByAddress(final String address) { final Uri uri = Uri.withAppendedPath(ContactsContract.CommonDataKinds.Email.CONTENT_LOOKUP_URI, Uri.encode(address)); final Uri uri = Uri.withAppendedPath(ContactsContract.CommonDataKinds.Email.CONTENT_LOOKUP_URI, Uri.encode(address)); if (hasContactPermission()) { return mContentResolver.query( return mContentResolver.query( uri, uri, PROJECTION, PROJECTION, null, null, null, null, SORT_ORDER); SORT_ORDER); } else { return new EmptyCursor(); } } } /** /** Loading app/core/src/main/java/com/fsck/k9/helper/EmptyCursor.java 0 → 100644 +54 −0 Original line number Original line Diff line number Diff line package com.fsck.k9.helper; import android.database.AbstractCursor; /** * A dummy class that provides a empty cursor */ public class EmptyCursor extends AbstractCursor { @Override public int getCount() { return 0; } @Override public String[] getColumnNames() { return new String[0]; } @Override public String getString(int column) { return null; } @Override public short getShort(int column) { return 0; } @Override public int getInt(int column) { return 0; } @Override public long getLong(int column) { return 0; } @Override public float getFloat(int column) { return 0; } @Override public double getDouble(int column) { return 0; } @Override public boolean isNull(int column) { return false; } } No newline at end of file app/k9mail/build.gradle +1 −1 Original line number Original line Diff line number Diff line Loading @@ -46,7 +46,7 @@ android { versionName '5.700-SNAPSHOT' versionName '5.700-SNAPSHOT' minSdkVersion buildConfig.minSdk minSdkVersion buildConfig.minSdk targetSdkVersion 22 targetSdkVersion 23 generatedDensities = ['mdpi', 'hdpi', 'xhdpi'] generatedDensities = ['mdpi', 'hdpi', 'xhdpi'] Loading app/ui/build.gradle +1 −1 Original line number Original line Diff line number Diff line Loading @@ -61,7 +61,7 @@ android { defaultConfig { defaultConfig { minSdkVersion buildConfig.minSdk minSdkVersion buildConfig.minSdk // For Robolectric tests // For Robolectric tests targetSdkVersion 22 targetSdkVersion 23 } } lintOptions { lintOptions { Loading app/ui/src/main/java/com/fsck/k9/activity/K9Activity.java +62 −0 Original line number Original line Diff line number Diff line package com.fsck.k9.activity; package com.fsck.k9.activity; import android.Manifest; import android.content.pm.PackageManager; import android.os.Bundle; import android.os.Bundle; import android.support.annotation.StringRes; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity; import android.view.MotionEvent; import android.view.MotionEvent; import com.fsck.k9.activity.K9ActivityCommon.K9ActivityMagic; import com.fsck.k9.activity.K9ActivityCommon.K9ActivityMagic; import com.fsck.k9.activity.misc.SwipeGestureDetector.OnSwipeGestureListener; import com.fsck.k9.activity.misc.SwipeGestureDetector.OnSwipeGestureListener; import com.fsck.k9.ui.R; import com.fsck.k9.ui.permissions.PermissionRationaleDialogFragment; import timber.log.Timber; public abstract class K9Activity extends AppCompatActivity implements K9ActivityMagic { public abstract class K9Activity extends AppCompatActivity implements K9ActivityMagic { public static final int PERMISSIONS_REQUEST_READ_CONTACTS = 1; public static final int PERMISSIONS_REQUEST_WRITE_CONTACTS = 2; private static final String FRAGMENT_TAG_RATIONALE = "rationale"; private K9ActivityCommon mBase; private K9ActivityCommon mBase; Loading @@ -29,4 +42,53 @@ public abstract class K9Activity extends AppCompatActivity implements K9Activity public void setupGestureDetector(OnSwipeGestureListener listener) { public void setupGestureDetector(OnSwipeGestureListener listener) { mBase.setupGestureDetector(listener); mBase.setupGestureDetector(listener); } } public boolean hasPermission(Permission permission) { return ContextCompat.checkSelfPermission(this, permission.permission) == PackageManager.PERMISSION_GRANTED; } public void requestPermissionOrShowRationale(Permission permission) { if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission.permission)) { PermissionRationaleDialogFragment dialogFragment = PermissionRationaleDialogFragment.newInstance(permission); dialogFragment.show(getSupportFragmentManager(), FRAGMENT_TAG_RATIONALE); } else { requestPermission(permission); } } public void requestPermission(Permission permission) { Timber.i("Requesting permission: " + permission.permission); ActivityCompat.requestPermissions(this, new String[] { permission.permission }, permission.requestCode); } public enum Permission { READ_CONTACTS( Manifest.permission.READ_CONTACTS, PERMISSIONS_REQUEST_READ_CONTACTS, R.string.permission_contacts_rationale_title, R.string.permission_contacts_rationale_message ), WRITE_CONTACTS( Manifest.permission.WRITE_CONTACTS, PERMISSIONS_REQUEST_WRITE_CONTACTS, R.string.permission_contacts_rationale_title, R.string.permission_contacts_rationale_message ); public final String permission; public final int requestCode; public final int rationaleTitle; public final int rationaleMessage; Permission(String permission, int requestCode, @StringRes int rationaleTitle, @StringRes int rationaleMessage) { this.permission = permission; this.requestCode = requestCode; this.rationaleTitle = rationaleTitle; this.rationaleMessage = rationaleMessage; } } } } Loading
app/core/src/main/java/com/fsck/k9/helper/Contacts.java +23 −6 Original line number Original line Diff line number Diff line package com.fsck.k9.helper; package com.fsck.k9.helper; import android.Manifest; import android.content.ContentResolver; import android.content.ContentResolver; import android.content.Context; import android.content.Context; import android.content.Intent; import android.content.Intent; import android.content.pm.PackageManager; import android.database.AbstractCursor; import android.database.Cursor; import android.database.Cursor; import android.net.Uri; import android.net.Uri; import android.provider.ContactsContract; import android.provider.ContactsContract; import timber.log.Timber; import timber.log.Timber; import android.provider.ContactsContract.CommonDataKinds.Photo; import android.provider.ContactsContract.CommonDataKinds.Photo; import android.support.v4.content.ContextCompat; import com.fsck.k9.mail.Address; import com.fsck.k9.mail.Address; Loading Loading @@ -263,6 +267,14 @@ public class Contacts { } } } } private boolean hasContactPermission() { boolean canRead = ContextCompat.checkSelfPermission(mContext, Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED; boolean canWrite = ContextCompat.checkSelfPermission(mContext, Manifest.permission.WRITE_CONTACTS) == PackageManager.PERMISSION_GRANTED; return canRead && canWrite; } /** /** * Return a {@link Cursor} instance that can be used to fetch information * Return a {@link Cursor} instance that can be used to fetch information * about the contact with the given email address. * about the contact with the given email address. Loading @@ -273,12 +285,17 @@ public class Contacts { */ */ private Cursor getContactByAddress(final String address) { private Cursor getContactByAddress(final String address) { final Uri uri = Uri.withAppendedPath(ContactsContract.CommonDataKinds.Email.CONTENT_LOOKUP_URI, Uri.encode(address)); final Uri uri = Uri.withAppendedPath(ContactsContract.CommonDataKinds.Email.CONTENT_LOOKUP_URI, Uri.encode(address)); if (hasContactPermission()) { return mContentResolver.query( return mContentResolver.query( uri, uri, PROJECTION, PROJECTION, null, null, null, null, SORT_ORDER); SORT_ORDER); } else { return new EmptyCursor(); } } } /** /** Loading
app/core/src/main/java/com/fsck/k9/helper/EmptyCursor.java 0 → 100644 +54 −0 Original line number Original line Diff line number Diff line package com.fsck.k9.helper; import android.database.AbstractCursor; /** * A dummy class that provides a empty cursor */ public class EmptyCursor extends AbstractCursor { @Override public int getCount() { return 0; } @Override public String[] getColumnNames() { return new String[0]; } @Override public String getString(int column) { return null; } @Override public short getShort(int column) { return 0; } @Override public int getInt(int column) { return 0; } @Override public long getLong(int column) { return 0; } @Override public float getFloat(int column) { return 0; } @Override public double getDouble(int column) { return 0; } @Override public boolean isNull(int column) { return false; } } No newline at end of file
app/k9mail/build.gradle +1 −1 Original line number Original line Diff line number Diff line Loading @@ -46,7 +46,7 @@ android { versionName '5.700-SNAPSHOT' versionName '5.700-SNAPSHOT' minSdkVersion buildConfig.minSdk minSdkVersion buildConfig.minSdk targetSdkVersion 22 targetSdkVersion 23 generatedDensities = ['mdpi', 'hdpi', 'xhdpi'] generatedDensities = ['mdpi', 'hdpi', 'xhdpi'] Loading
app/ui/build.gradle +1 −1 Original line number Original line Diff line number Diff line Loading @@ -61,7 +61,7 @@ android { defaultConfig { defaultConfig { minSdkVersion buildConfig.minSdk minSdkVersion buildConfig.minSdk // For Robolectric tests // For Robolectric tests targetSdkVersion 22 targetSdkVersion 23 } } lintOptions { lintOptions { Loading
app/ui/src/main/java/com/fsck/k9/activity/K9Activity.java +62 −0 Original line number Original line Diff line number Diff line package com.fsck.k9.activity; package com.fsck.k9.activity; import android.Manifest; import android.content.pm.PackageManager; import android.os.Bundle; import android.os.Bundle; import android.support.annotation.StringRes; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity; import android.view.MotionEvent; import android.view.MotionEvent; import com.fsck.k9.activity.K9ActivityCommon.K9ActivityMagic; import com.fsck.k9.activity.K9ActivityCommon.K9ActivityMagic; import com.fsck.k9.activity.misc.SwipeGestureDetector.OnSwipeGestureListener; import com.fsck.k9.activity.misc.SwipeGestureDetector.OnSwipeGestureListener; import com.fsck.k9.ui.R; import com.fsck.k9.ui.permissions.PermissionRationaleDialogFragment; import timber.log.Timber; public abstract class K9Activity extends AppCompatActivity implements K9ActivityMagic { public abstract class K9Activity extends AppCompatActivity implements K9ActivityMagic { public static final int PERMISSIONS_REQUEST_READ_CONTACTS = 1; public static final int PERMISSIONS_REQUEST_WRITE_CONTACTS = 2; private static final String FRAGMENT_TAG_RATIONALE = "rationale"; private K9ActivityCommon mBase; private K9ActivityCommon mBase; Loading @@ -29,4 +42,53 @@ public abstract class K9Activity extends AppCompatActivity implements K9Activity public void setupGestureDetector(OnSwipeGestureListener listener) { public void setupGestureDetector(OnSwipeGestureListener listener) { mBase.setupGestureDetector(listener); mBase.setupGestureDetector(listener); } } public boolean hasPermission(Permission permission) { return ContextCompat.checkSelfPermission(this, permission.permission) == PackageManager.PERMISSION_GRANTED; } public void requestPermissionOrShowRationale(Permission permission) { if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission.permission)) { PermissionRationaleDialogFragment dialogFragment = PermissionRationaleDialogFragment.newInstance(permission); dialogFragment.show(getSupportFragmentManager(), FRAGMENT_TAG_RATIONALE); } else { requestPermission(permission); } } public void requestPermission(Permission permission) { Timber.i("Requesting permission: " + permission.permission); ActivityCompat.requestPermissions(this, new String[] { permission.permission }, permission.requestCode); } public enum Permission { READ_CONTACTS( Manifest.permission.READ_CONTACTS, PERMISSIONS_REQUEST_READ_CONTACTS, R.string.permission_contacts_rationale_title, R.string.permission_contacts_rationale_message ), WRITE_CONTACTS( Manifest.permission.WRITE_CONTACTS, PERMISSIONS_REQUEST_WRITE_CONTACTS, R.string.permission_contacts_rationale_title, R.string.permission_contacts_rationale_message ); public final String permission; public final int requestCode; public final int rationaleTitle; public final int rationaleMessage; Permission(String permission, int requestCode, @StringRes int rationaleTitle, @StringRes int rationaleMessage) { this.permission = permission; this.requestCode = requestCode; this.rationaleTitle = rationaleTitle; this.rationaleMessage = rationaleMessage; } } } }