make contact integration depend on manifest, not flavor
This commit is contained in:
parent
9b832e1285
commit
8e73b7f477
|
@ -62,8 +62,8 @@ public class JabberIdContact extends AbstractPhoneContact {
|
||||||
return jid;
|
return jid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Map<Jid, JabberIdContact> load(Context context) {
|
public static Map<Jid, JabberIdContact> load(final Context context) {
|
||||||
if (!QuickConversationsService.isFreeOrQuicksyFlavor()
|
if (!QuickConversationsService.isContactListIntegration(context)
|
||||||
|| (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
|| (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
||||||
&& context.checkSelfPermission(Manifest.permission.READ_CONTACTS)
|
&& context.checkSelfPermission(Manifest.permission.READ_CONTACTS)
|
||||||
!= PackageManager.PERMISSION_GRANTED)) {
|
!= PackageManager.PERMISSION_GRANTED)) {
|
||||||
|
|
|
@ -1,14 +1,22 @@
|
||||||
package eu.siacs.conversations.services;
|
package eu.siacs.conversations.services;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Build;
|
import android.content.pm.PackageManager;
|
||||||
|
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
|
||||||
import eu.siacs.conversations.BuildConfig;
|
import eu.siacs.conversations.BuildConfig;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
public abstract class AbstractQuickConversationsService {
|
public abstract class AbstractQuickConversationsService {
|
||||||
|
|
||||||
|
public static final String SMS_RETRIEVED_ACTION =
|
||||||
|
"com.google.android.gms.auth.api.phone.SMS_RETRIEVED";
|
||||||
|
|
||||||
public static final String SMS_RETRIEVED_ACTION = "com.google.android.gms.auth.api.phone.SMS_RETRIEVED";
|
private static Boolean declaredReadContacts = null;
|
||||||
|
|
||||||
protected final XmppConnectionService service;
|
protected final XmppConnectionService service;
|
||||||
|
|
||||||
|
@ -30,8 +38,31 @@ public abstract class AbstractQuickConversationsService {
|
||||||
return "playstore".equals(BuildConfig.FLAVOR_distribution);
|
return "playstore".equals(BuildConfig.FLAVOR_distribution);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isFreeOrQuicksyFlavor() {
|
public static boolean isContactListIntegration(final Context context) {
|
||||||
return "free".equals(BuildConfig.FLAVOR_distribution) || "quicksy".equals(BuildConfig.FLAVOR_mode);
|
if ("quicksy".equals(BuildConfig.FLAVOR_mode)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
final var readContacts = AbstractQuickConversationsService.declaredReadContacts;
|
||||||
|
if (readContacts != null) {
|
||||||
|
return Boolean.TRUE.equals(readContacts);
|
||||||
|
}
|
||||||
|
AbstractQuickConversationsService.declaredReadContacts = hasDeclaredReadContacts(context);
|
||||||
|
return AbstractQuickConversationsService.declaredReadContacts;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean hasDeclaredReadContacts(final Context context) {
|
||||||
|
final String[] permissions;
|
||||||
|
try {
|
||||||
|
permissions =
|
||||||
|
context.getPackageManager()
|
||||||
|
.getPackageInfo(
|
||||||
|
context.getPackageName(), PackageManager.GET_PERMISSIONS)
|
||||||
|
.requestedPermissions;
|
||||||
|
} catch (final PackageManager.NameNotFoundException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return Iterables.any(
|
||||||
|
Arrays.asList(permissions), p -> p.equals(Manifest.permission.READ_CONTACTS));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isQuicksyPlayStore() {
|
public static boolean isQuicksyPlayStore() {
|
||||||
|
|
|
@ -1290,7 +1290,7 @@ public class XmppConnectionService extends Service {
|
||||||
|
|
||||||
restoreFromDatabase();
|
restoreFromDatabase();
|
||||||
|
|
||||||
if (QuickConversationsService.isFreeOrQuicksyFlavor()
|
if (QuickConversationsService.isContactListIntegration(this)
|
||||||
&& (Build.VERSION.SDK_INT < Build.VERSION_CODES.M
|
&& (Build.VERSION.SDK_INT < Build.VERSION_CODES.M
|
||||||
|| ContextCompat.checkSelfPermission(
|
|| ContextCompat.checkSelfPermission(
|
||||||
this, Manifest.permission.READ_CONTACTS)
|
this, Manifest.permission.READ_CONTACTS)
|
||||||
|
|
|
@ -120,13 +120,13 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
|
||||||
private void checkContactPermissionAndShowAddDialog() {
|
private void checkContactPermissionAndShowAddDialog() {
|
||||||
if (hasContactsPermission()) {
|
if (hasContactsPermission()) {
|
||||||
showAddToPhoneBookDialog();
|
showAddToPhoneBookDialog();
|
||||||
} else if (QuickConversationsService.isFreeOrQuicksyFlavor() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
} else if (QuickConversationsService.isContactListIntegration(this) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, REQUEST_SYNC_CONTACTS);
|
requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, REQUEST_SYNC_CONTACTS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasContactsPermission() {
|
private boolean hasContactsPermission() {
|
||||||
if (QuickConversationsService.isFreeOrQuicksyFlavor() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (QuickConversationsService.isContactListIntegration(this) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
return checkSelfPermission(Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED;
|
return checkSelfPermission(Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED;
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
|
@ -525,7 +525,7 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onBadgeClick(final View view) {
|
private void onBadgeClick(final View view) {
|
||||||
if (QuickConversationsService.isFreeOrQuicksyFlavor()) {
|
if (QuickConversationsService.isContactListIntegration(this)) {
|
||||||
final Uri systemAccount = contact.getSystemAccount();
|
final Uri systemAccount = contact.getSystemAccount();
|
||||||
if (systemAccount == null) {
|
if (systemAccount == null) {
|
||||||
checkContactPermissionAndShowAddDialog();
|
checkContactPermissionAndShowAddDialog();
|
||||||
|
|
|
@ -6,12 +6,14 @@ import android.app.Dialog;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.content.ActivityNotFoundException;
|
import android.content.ActivityNotFoundException;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.Html;
|
import android.text.Html;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
|
@ -91,6 +93,8 @@ import eu.siacs.conversations.xmpp.XmppConnection;
|
||||||
|
|
||||||
public class StartConversationActivity extends XmppActivity implements XmppConnectionService.OnConversationUpdate, OnRosterUpdate, OnUpdateBlocklist, CreatePrivateGroupChatDialog.CreateConferenceDialogListener, JoinConferenceDialog.JoinConferenceDialogListener, SwipeRefreshLayout.OnRefreshListener, CreatePublicChannelDialog.CreatePublicChannelDialogListener {
|
public class StartConversationActivity extends XmppActivity implements XmppConnectionService.OnConversationUpdate, OnRosterUpdate, OnUpdateBlocklist, CreatePrivateGroupChatDialog.CreateConferenceDialogListener, JoinConferenceDialog.JoinConferenceDialogListener, SwipeRefreshLayout.OnRefreshListener, CreatePublicChannelDialog.CreatePublicChannelDialogListener {
|
||||||
|
|
||||||
|
private static final String PREF_KEY_CONTACT_INTEGRATION_CONSENT = "contact_list_integration_consent";
|
||||||
|
|
||||||
public static final String EXTRA_INVITE_URI = "eu.siacs.conversations.invite_uri";
|
public static final String EXTRA_INVITE_URI = "eu.siacs.conversations.invite_uri";
|
||||||
|
|
||||||
private final int REQUEST_SYNC_CONTACTS = 0x28cf;
|
private final int REQUEST_SYNC_CONTACTS = 0x28cf;
|
||||||
|
@ -761,42 +765,86 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
|
||||||
}
|
}
|
||||||
|
|
||||||
private void askForContactsPermissions() {
|
private void askForContactsPermissions() {
|
||||||
if (QuickConversationsService.isFreeOrQuicksyFlavor() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (QuickConversationsService.isContactListIntegration(this)
|
||||||
if (checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
|
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
|
if (checkSelfPermission(Manifest.permission.READ_CONTACTS)
|
||||||
|
!= PackageManager.PERMISSION_GRANTED) {
|
||||||
if (mRequestedContactsPermission.compareAndSet(false, true)) {
|
if (mRequestedContactsPermission.compareAndSet(false, true)) {
|
||||||
if (QuickConversationsService.isQuicksy() || shouldShowRequestPermissionRationale(Manifest.permission.READ_CONTACTS)) {
|
final String consent =
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(getApplicationContext())
|
||||||
|
.getString(PREF_KEY_CONTACT_INTEGRATION_CONSENT, null);
|
||||||
|
final boolean requiresConsent =
|
||||||
|
(QuickConversationsService.isQuicksy()
|
||||||
|
|| QuickConversationsService.isPlayStoreFlavor())
|
||||||
|
&& !"agreed".equals(consent);
|
||||||
|
if (requiresConsent && "declined".equals(consent)) {
|
||||||
|
Log.d(Config.LOGTAG,"not asking for contacts permission because consent has been declined");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (requiresConsent
|
||||||
|
|| shouldShowRequestPermissionRationale(
|
||||||
|
Manifest.permission.READ_CONTACTS)) {
|
||||||
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||||
final AtomicBoolean requestPermission = new AtomicBoolean(false);
|
final AtomicBoolean requestPermission = new AtomicBoolean(false);
|
||||||
if (QuickConversationsService.isQuicksy()) {
|
if (QuickConversationsService.isQuicksy()) {
|
||||||
builder.setTitle(R.string.quicksy_wants_your_consent);
|
builder.setTitle(R.string.quicksy_wants_your_consent);
|
||||||
builder.setMessage(Html.fromHtml(getString(R.string.sync_with_contacts_quicksy_static)));
|
builder.setMessage(
|
||||||
|
Html.fromHtml(
|
||||||
|
getString(R.string.sync_with_contacts_quicksy_static)));
|
||||||
} else {
|
} else {
|
||||||
builder.setTitle(R.string.sync_with_contacts);
|
builder.setTitle(R.string.sync_with_contacts);
|
||||||
builder.setMessage(getString(R.string.sync_with_contacts_long, getString(R.string.app_name)));
|
builder.setMessage(
|
||||||
|
getString(
|
||||||
|
R.string.sync_with_contacts_long,
|
||||||
|
getString(R.string.app_name)));
|
||||||
}
|
}
|
||||||
@StringRes int confirmButtonText;
|
@StringRes int confirmButtonText;
|
||||||
if (QuickConversationsService.isConversations()) {
|
if (requiresConsent) {
|
||||||
confirmButtonText = R.string.next;
|
|
||||||
} else {
|
|
||||||
confirmButtonText = R.string.agree_and_continue;
|
confirmButtonText = R.string.agree_and_continue;
|
||||||
|
} else {
|
||||||
|
confirmButtonText = R.string.next;
|
||||||
|
}
|
||||||
|
builder.setPositiveButton(
|
||||||
|
confirmButtonText,
|
||||||
|
(dialog, which) -> {
|
||||||
|
if (requiresConsent) {
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(
|
||||||
|
getApplicationContext())
|
||||||
|
.edit()
|
||||||
|
.putString(
|
||||||
|
PREF_KEY_CONTACT_INTEGRATION_CONSENT, "agreed")
|
||||||
|
.apply();
|
||||||
}
|
}
|
||||||
builder.setPositiveButton(confirmButtonText, (dialog, which) -> {
|
|
||||||
if (requestPermission.compareAndSet(false, true)) {
|
if (requestPermission.compareAndSet(false, true)) {
|
||||||
requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, REQUEST_SYNC_CONTACTS);
|
requestPermissions(
|
||||||
|
new String[] {Manifest.permission.READ_CONTACTS},
|
||||||
|
REQUEST_SYNC_CONTACTS);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
builder.setOnDismissListener(dialog -> {
|
if (requiresConsent) {
|
||||||
if (QuickConversationsService.isConversations() && requestPermission.compareAndSet(false, true)) {
|
builder.setNegativeButton(R.string.decline, (dialog, which) -> PreferenceManager.getDefaultSharedPreferences(
|
||||||
requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, REQUEST_SYNC_CONTACTS);
|
getApplicationContext())
|
||||||
|
.edit()
|
||||||
|
.putString(
|
||||||
|
PREF_KEY_CONTACT_INTEGRATION_CONSENT, "declined")
|
||||||
|
.apply());
|
||||||
|
} else {
|
||||||
|
builder.setOnDismissListener(
|
||||||
|
dialog -> {
|
||||||
|
if (requestPermission.compareAndSet(false, true)) {
|
||||||
|
requestPermissions(
|
||||||
|
new String[] {
|
||||||
|
Manifest.permission.READ_CONTACTS
|
||||||
|
},
|
||||||
|
REQUEST_SYNC_CONTACTS);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (QuickConversationsService.isQuicksy()) {
|
|
||||||
builder.setNegativeButton(R.string.decline, null);
|
|
||||||
}
|
}
|
||||||
builder.setCancelable(QuickConversationsService.isQuicksy());
|
builder.setCancelable(requiresConsent);
|
||||||
final AlertDialog dialog = builder.create();
|
final AlertDialog dialog = builder.create();
|
||||||
dialog.setCanceledOnTouchOutside(QuickConversationsService.isQuicksy());
|
dialog.setCanceledOnTouchOutside(requiresConsent);
|
||||||
dialog.setOnShowListener(dialogInterface -> {
|
dialog.setOnShowListener(
|
||||||
|
dialogInterface -> {
|
||||||
final TextView tv = dialog.findViewById(android.R.id.message);
|
final TextView tv = dialog.findViewById(android.R.id.message);
|
||||||
if (tv != null) {
|
if (tv != null) {
|
||||||
tv.setMovementMethod(LinkMovementMethod.getInstance());
|
tv.setMovementMethod(LinkMovementMethod.getInstance());
|
||||||
|
@ -804,7 +852,9 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
|
||||||
});
|
});
|
||||||
dialog.show();
|
dialog.show();
|
||||||
} else {
|
} else {
|
||||||
requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, REQUEST_SYNC_CONTACTS);
|
requestPermissions(
|
||||||
|
new String[] {Manifest.permission.READ_CONTACTS},
|
||||||
|
REQUEST_SYNC_CONTACTS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -840,7 +890,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onBackendConnected() {
|
protected void onBackendConnected() {
|
||||||
if (QuickConversationsService.isFreeOrQuicksyFlavor()
|
if (QuickConversationsService.isContactListIntegration(this)
|
||||||
&& (Build.VERSION.SDK_INT < Build.VERSION_CODES.M
|
&& (Build.VERSION.SDK_INT < Build.VERSION_CODES.M
|
||||||
|| checkSelfPermission(Manifest.permission.READ_CONTACTS)
|
|| checkSelfPermission(Manifest.permission.READ_CONTACTS)
|
||||||
== PackageManager.PERMISSION_GRANTED)) {
|
== PackageManager.PERMISSION_GRANTED)) {
|
||||||
|
|
|
@ -10,6 +10,8 @@ import android.os.Build;
|
||||||
import android.provider.ContactsContract.Profile;
|
import android.provider.ContactsContract.Profile;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
|
||||||
|
import com.google.common.base.Strings;
|
||||||
|
|
||||||
import eu.siacs.conversations.services.QuickConversationsService;
|
import eu.siacs.conversations.services.QuickConversationsService;
|
||||||
|
|
||||||
public class PhoneHelper {
|
public class PhoneHelper {
|
||||||
|
@ -20,27 +22,25 @@ public class PhoneHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Uri getProfilePictureUri(final Context context) {
|
public static Uri getProfilePictureUri(final Context context) {
|
||||||
if (!QuickConversationsService.isFreeOrQuicksyFlavor()
|
if (!QuickConversationsService.isContactListIntegration(context)
|
||||||
|| (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
|| (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
||||||
&& context.checkSelfPermission(Manifest.permission.READ_CONTACTS)
|
&& context.checkSelfPermission(Manifest.permission.READ_CONTACTS)
|
||||||
!= PackageManager.PERMISSION_GRANTED)) {
|
!= PackageManager.PERMISSION_GRANTED)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
final String[] projection = new String[] {Profile._ID, Profile.PHOTO_URI};
|
final String[] projection = new String[] {Profile._ID, Profile.PHOTO_URI};
|
||||||
final Cursor cursor;
|
try (final Cursor cursor =
|
||||||
try {
|
|
||||||
cursor =
|
|
||||||
context.getContentResolver()
|
context.getContentResolver()
|
||||||
.query(Profile.CONTENT_URI, projection, null, null, null);
|
.query(Profile.CONTENT_URI, projection, null, null, null)) {
|
||||||
} catch (Throwable e) {
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
|
final var photoUri = cursor.getString(1);
|
||||||
|
if (Strings.isNullOrEmpty(photoUri)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (cursor == null) {
|
return Uri.parse(photoUri);
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
final String uri = cursor.moveToFirst() ? cursor.getString(1) : null;
|
}
|
||||||
cursor.close();
|
return null;
|
||||||
return uri == null ? null : Uri.parse(uri);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isEmulator() {
|
public static boolean isEmulator() {
|
||||||
|
|
|
@ -518,8 +518,8 @@
|
||||||
<string name="no_storage_permission">Grant %1$s access to external storage</string>
|
<string name="no_storage_permission">Grant %1$s access to external storage</string>
|
||||||
<string name="no_camera_permission">Grant %1$s access to the camera</string>
|
<string name="no_camera_permission">Grant %1$s access to the camera</string>
|
||||||
<string name="quicksy_wants_your_consent">Quicksy asks for your consent to use your data</string>
|
<string name="quicksy_wants_your_consent">Quicksy asks for your consent to use your data</string>
|
||||||
<string name="sync_with_contacts">Synchronize with contacts</string>
|
<string name="sync_with_contacts">Contact list integration</string>
|
||||||
<string name="sync_with_contacts_long">%1$s wants permission to access your address book to match it with your XMPP contact list.\nThis will display your contacts’ full names and avatars.\n\n%1$s will only read your address book and match it locally without uploading anything to your server.</string>
|
<string name="sync_with_contacts_long">%1$s processes your contact list locally, on your device, to show you the names and profile pictures for matching contacts on XMPP.\n\nNo contact list data ever leaves your device!</string>
|
||||||
<string name="sync_with_contacts_quicksy_static" translatable="false"><![CDATA[Quicksy syncs your contact list in regular intervals to make suggestions about possible contacts, who are already using the app, even when the app is closed or not in use.<br><br>Find more information in our <a href="https://quicksy.im/privacy.htm">Privacy Policy</a>.]]></string>
|
<string name="sync_with_contacts_quicksy_static" translatable="false"><![CDATA[Quicksy syncs your contact list in regular intervals to make suggestions about possible contacts, who are already using the app, even when the app is closed or not in use.<br><br>Find more information in our <a href="https://quicksy.im/privacy.htm">Privacy Policy</a>.]]></string>
|
||||||
<string name="notify_on_all_messages">Notify on all messages</string>
|
<string name="notify_on_all_messages">Notify on all messages</string>
|
||||||
<string name="notify_only_when_highlighted">Notify only when mentioned</string>
|
<string name="notify_only_when_highlighted">Notify only when mentioned</string>
|
||||||
|
@ -1024,5 +1024,5 @@
|
||||||
<string name="report_spam">Report spam</string>
|
<string name="report_spam">Report spam</string>
|
||||||
<string name="report_spam_and_block">Report spam and block spammer</string>
|
<string name="report_spam_and_block">Report spam and block spammer</string>
|
||||||
<string name="privacy_policy">Privacy policy</string>
|
<string name="privacy_policy">Privacy policy</string>
|
||||||
<string name="contact_list_integration_not_available">Address book integration is not available</string>
|
<string name="contact_list_integration_not_available">Contact list integration is not available</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in a new issue