request READ_MEDIA_* permission when restoring backup on fdroid version
This commit is contained in:
parent
7088c1f507
commit
9cabc0262f
|
@ -58,6 +58,7 @@ import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -188,12 +189,7 @@ public class ImportBackupService extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Collections.sort(
|
Collections.sort(
|
||||||
backupFiles,
|
backupFiles, Comparator.comparing(a -> a.header.getJid().toString()));
|
||||||
(a, b) ->
|
|
||||||
a.header
|
|
||||||
.getJid()
|
|
||||||
.toString()
|
|
||||||
.compareTo(b.header.getJid().toString()));
|
|
||||||
onBackupFilesLoaded.onBackupFilesLoaded(backupFiles);
|
onBackupFilesLoaded.onBackupFilesLoaded(backupFiles);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
package eu.siacs.conversations.ui;
|
package eu.siacs.conversations.ui;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.ServiceConnection;
|
import android.content.ServiceConnection;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
@ -14,15 +17,16 @@ import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
import androidx.databinding.DataBindingUtil;
|
import androidx.databinding.DataBindingUtil;
|
||||||
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
import java.io.IOException;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import eu.siacs.conversations.Config;
|
import eu.siacs.conversations.Config;
|
||||||
import eu.siacs.conversations.R;
|
import eu.siacs.conversations.R;
|
||||||
|
@ -30,10 +34,18 @@ import eu.siacs.conversations.databinding.ActivityImportBackupBinding;
|
||||||
import eu.siacs.conversations.databinding.DialogEnterPasswordBinding;
|
import eu.siacs.conversations.databinding.DialogEnterPasswordBinding;
|
||||||
import eu.siacs.conversations.services.ImportBackupService;
|
import eu.siacs.conversations.services.ImportBackupService;
|
||||||
import eu.siacs.conversations.ui.adapter.BackupFileAdapter;
|
import eu.siacs.conversations.ui.adapter.BackupFileAdapter;
|
||||||
import eu.siacs.conversations.ui.util.SettingsUtils;
|
|
||||||
import eu.siacs.conversations.utils.BackupFileHeader;
|
import eu.siacs.conversations.utils.BackupFileHeader;
|
||||||
|
|
||||||
public class ImportBackupActivity extends ActionBarActivity implements ServiceConnection, ImportBackupService.OnBackupFilesLoaded, BackupFileAdapter.OnItemClickedListener, ImportBackupService.OnBackupProcessed {
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class ImportBackupActivity extends ActionBarActivity
|
||||||
|
implements ServiceConnection,
|
||||||
|
ImportBackupService.OnBackupFilesLoaded,
|
||||||
|
BackupFileAdapter.OnItemClickedListener,
|
||||||
|
ImportBackupService.OnBackupProcessed {
|
||||||
|
|
||||||
private ActivityImportBackupBinding binding;
|
private ActivityImportBackupBinding binding;
|
||||||
|
|
||||||
|
@ -41,8 +53,18 @@ public class ImportBackupActivity extends ActionBarActivity implements ServiceCo
|
||||||
private ImportBackupService service;
|
private ImportBackupService service;
|
||||||
|
|
||||||
private boolean mLoadingState = false;
|
private boolean mLoadingState = false;
|
||||||
|
private final ActivityResultLauncher<String[]> requestPermissions =
|
||||||
private int mTheme;
|
registerForActivityResult(
|
||||||
|
new ActivityResultContracts.RequestMultiplePermissions(),
|
||||||
|
results -> {
|
||||||
|
if (results.containsValue(Boolean.TRUE)) {
|
||||||
|
final var service = this.service;
|
||||||
|
if (service == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
service.loadBackupFiles(this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(final Bundle savedInstanceState) {
|
protected void onCreate(final Bundle savedInstanceState) {
|
||||||
|
@ -50,7 +72,9 @@ public class ImportBackupActivity extends ActionBarActivity implements ServiceCo
|
||||||
binding = DataBindingUtil.setContentView(this, R.layout.activity_import_backup);
|
binding = DataBindingUtil.setContentView(this, R.layout.activity_import_backup);
|
||||||
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
|
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
|
||||||
setSupportActionBar(binding.toolbar);
|
setSupportActionBar(binding.toolbar);
|
||||||
setLoadingState(savedInstanceState != null && savedInstanceState.getBoolean("loading_state", false));
|
setLoadingState(
|
||||||
|
savedInstanceState != null
|
||||||
|
&& savedInstanceState.getBoolean("loading_state", false));
|
||||||
this.backupFileAdapter = new BackupFileAdapter();
|
this.backupFileAdapter = new BackupFileAdapter();
|
||||||
this.binding.list.setAdapter(this.backupFileAdapter);
|
this.binding.list.setAdapter(this.backupFileAdapter);
|
||||||
this.backupFileAdapter.setOnItemClickedListener(this);
|
this.backupFileAdapter.setOnItemClickedListener(this);
|
||||||
|
@ -72,15 +96,55 @@ public class ImportBackupActivity extends ActionBarActivity implements ServiceCo
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
|
|
||||||
super.onStart();
|
super.onStart();
|
||||||
bindService(new Intent(this, ImportBackupService.class), this, Context.BIND_AUTO_CREATE);
|
bindService(new Intent(this, ImportBackupService.class), this, Context.BIND_AUTO_CREATE);
|
||||||
final Intent intent = getIntent();
|
final Intent intent = getIntent();
|
||||||
if (intent != null && Intent.ACTION_VIEW.equals(intent.getAction()) && !this.mLoadingState) {
|
if (intent != null
|
||||||
|
&& Intent.ACTION_VIEW.equals(intent.getAction())
|
||||||
|
&& !this.mLoadingState) {
|
||||||
Uri uri = intent.getData();
|
Uri uri = intent.getData();
|
||||||
if (uri != null) {
|
if (uri != null) {
|
||||||
openBackupFileFromUri(uri, true);
|
openBackupFileFromUri(uri, true);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
final List<String> desiredPermission;
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||||
|
desiredPermission =
|
||||||
|
ImmutableList.of(
|
||||||
|
Manifest.permission.READ_MEDIA_IMAGES,
|
||||||
|
Manifest.permission.READ_MEDIA_VIDEO,
|
||||||
|
Manifest.permission.READ_MEDIA_AUDIO,
|
||||||
|
Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED);
|
||||||
|
} else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
desiredPermission =
|
||||||
|
ImmutableList.of(
|
||||||
|
Manifest.permission.READ_MEDIA_IMAGES,
|
||||||
|
Manifest.permission.READ_MEDIA_VIDEO,
|
||||||
|
Manifest.permission.READ_MEDIA_AUDIO);
|
||||||
|
} else {
|
||||||
|
desiredPermission = ImmutableList.of(Manifest.permission.READ_EXTERNAL_STORAGE);
|
||||||
|
}
|
||||||
|
final Set<String> declaredPermission = getDeclaredPermission();
|
||||||
|
if (declaredPermission.containsAll(desiredPermission)) {
|
||||||
|
requestPermissions.launch(desiredPermission.toArray(new String[0]));
|
||||||
|
} else {
|
||||||
|
Log.d(Config.LOGTAG, "Manifest is lacking some desired permission. not requesting");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<String> getDeclaredPermission() {
|
||||||
|
final String[] permissions;
|
||||||
|
try {
|
||||||
|
permissions =
|
||||||
|
getPackageManager()
|
||||||
|
.getPackageInfo(getPackageName(), PackageManager.GET_PERMISSIONS)
|
||||||
|
.requestedPermissions;
|
||||||
|
} catch (final PackageManager.NameNotFoundException e) {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
return ImmutableSet.copyOf(permissions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -94,7 +158,8 @@ public class ImportBackupActivity extends ActionBarActivity implements ServiceCo
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||||
ImportBackupService.ImportBackupServiceBinder binder = (ImportBackupService.ImportBackupServiceBinder) service;
|
ImportBackupService.ImportBackupServiceBinder binder =
|
||||||
|
(ImportBackupService.ImportBackupServiceBinder) service;
|
||||||
this.service = binder.getService();
|
this.service = binder.getService();
|
||||||
this.service.addOnBackupProcessedListener(this);
|
this.service.addOnBackupProcessedListener(this);
|
||||||
setLoadingState(this.service.getLoadingState());
|
setLoadingState(this.service.getLoadingState());
|
||||||
|
@ -118,55 +183,81 @@ public class ImportBackupActivity extends ActionBarActivity implements ServiceCo
|
||||||
|
|
||||||
private void openBackupFileFromUri(final Uri uri, final boolean finishOnCancel) {
|
private void openBackupFileFromUri(final Uri uri, final boolean finishOnCancel) {
|
||||||
try {
|
try {
|
||||||
final ImportBackupService.BackupFile backupFile = ImportBackupService.BackupFile.read(this, uri);
|
final ImportBackupService.BackupFile backupFile =
|
||||||
|
ImportBackupService.BackupFile.read(this, uri);
|
||||||
showEnterPasswordDialog(backupFile, finishOnCancel);
|
showEnterPasswordDialog(backupFile, finishOnCancel);
|
||||||
} catch (final BackupFileHeader.OutdatedBackupFileVersion e) {
|
} catch (final BackupFileHeader.OutdatedBackupFileVersion e) {
|
||||||
Snackbar.make(binding.coordinator, R.string.outdated_backup_file_format, Snackbar.LENGTH_LONG).show();
|
Snackbar.make(
|
||||||
|
binding.coordinator,
|
||||||
|
R.string.outdated_backup_file_format,
|
||||||
|
Snackbar.LENGTH_LONG)
|
||||||
|
.show();
|
||||||
} catch (final IOException | IllegalArgumentException e) {
|
} catch (final IOException | IllegalArgumentException e) {
|
||||||
Log.d(Config.LOGTAG, "unable to open backup file " + uri, e);
|
Log.d(Config.LOGTAG, "unable to open backup file " + uri, e);
|
||||||
Snackbar.make(binding.coordinator, R.string.not_a_backup_file, Snackbar.LENGTH_LONG).show();
|
Snackbar.make(binding.coordinator, R.string.not_a_backup_file, Snackbar.LENGTH_LONG)
|
||||||
|
.show();
|
||||||
} catch (final SecurityException e) {
|
} catch (final SecurityException e) {
|
||||||
Snackbar.make(binding.coordinator, R.string.sharing_application_not_grant_permission, Snackbar.LENGTH_LONG).show();
|
Snackbar.make(
|
||||||
|
binding.coordinator,
|
||||||
|
R.string.sharing_application_not_grant_permission,
|
||||||
|
Snackbar.LENGTH_LONG)
|
||||||
|
.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showEnterPasswordDialog(final ImportBackupService.BackupFile backupFile, final boolean finishOnCancel) {
|
private void showEnterPasswordDialog(
|
||||||
final DialogEnterPasswordBinding enterPasswordBinding = DataBindingUtil.inflate(LayoutInflater.from(this), R.layout.dialog_enter_password, null, false);
|
final ImportBackupService.BackupFile backupFile, final boolean finishOnCancel) {
|
||||||
|
final DialogEnterPasswordBinding enterPasswordBinding =
|
||||||
|
DataBindingUtil.inflate(
|
||||||
|
LayoutInflater.from(this), R.layout.dialog_enter_password, null, false);
|
||||||
Log.d(Config.LOGTAG, "attempting to import " + backupFile.getUri());
|
Log.d(Config.LOGTAG, "attempting to import " + backupFile.getUri());
|
||||||
enterPasswordBinding.explain.setText(getString(R.string.enter_password_to_restore, backupFile.getHeader().getJid().toString()));
|
enterPasswordBinding.explain.setText(
|
||||||
|
getString(
|
||||||
|
R.string.enter_password_to_restore,
|
||||||
|
backupFile.getHeader().getJid().toString()));
|
||||||
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
|
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
|
||||||
builder.setView(enterPasswordBinding.getRoot());
|
builder.setView(enterPasswordBinding.getRoot());
|
||||||
builder.setTitle(R.string.enter_password);
|
builder.setTitle(R.string.enter_password);
|
||||||
builder.setNegativeButton(R.string.cancel, (dialog, which) -> {
|
builder.setNegativeButton(
|
||||||
if (finishOnCancel) {
|
R.string.cancel,
|
||||||
finish();
|
(dialog, which) -> {
|
||||||
}
|
if (finishOnCancel) {
|
||||||
});
|
finish();
|
||||||
|
}
|
||||||
|
});
|
||||||
builder.setPositiveButton(R.string.restore, null);
|
builder.setPositiveButton(R.string.restore, null);
|
||||||
builder.setCancelable(false);
|
builder.setCancelable(false);
|
||||||
final AlertDialog dialog = builder.create();
|
final AlertDialog dialog = builder.create();
|
||||||
dialog.setOnShowListener((d) -> {
|
dialog.setOnShowListener(
|
||||||
dialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(v -> {
|
(d) -> {
|
||||||
final String password = enterPasswordBinding.accountPassword.getEditableText().toString();
|
dialog.getButton(DialogInterface.BUTTON_POSITIVE)
|
||||||
if (password.isEmpty()) {
|
.setOnClickListener(
|
||||||
enterPasswordBinding.accountPasswordLayout.setError(getString(R.string.please_enter_password));
|
v -> {
|
||||||
return;
|
final String password =
|
||||||
}
|
enterPasswordBinding
|
||||||
final Uri uri = backupFile.getUri();
|
.accountPassword
|
||||||
Intent intent = new Intent(this, ImportBackupService.class);
|
.getEditableText()
|
||||||
intent.setAction(Intent.ACTION_SEND);
|
.toString();
|
||||||
intent.putExtra("password", password);
|
if (password.isEmpty()) {
|
||||||
if ("file".equals(uri.getScheme())) {
|
enterPasswordBinding.accountPasswordLayout.setError(
|
||||||
intent.putExtra("file", uri.getPath());
|
getString(R.string.please_enter_password));
|
||||||
} else {
|
return;
|
||||||
intent.setData(uri);
|
}
|
||||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
final Uri uri = backupFile.getUri();
|
||||||
}
|
Intent intent = new Intent(this, ImportBackupService.class);
|
||||||
setLoadingState(true);
|
intent.setAction(Intent.ACTION_SEND);
|
||||||
ContextCompat.startForegroundService(this, intent);
|
intent.putExtra("password", password);
|
||||||
d.dismiss();
|
if ("file".equals(uri.getScheme())) {
|
||||||
});
|
intent.putExtra("file", uri.getPath());
|
||||||
});
|
} else {
|
||||||
|
intent.setData(uri);
|
||||||
|
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
|
}
|
||||||
|
setLoadingState(true);
|
||||||
|
ContextCompat.startForegroundService(this, intent);
|
||||||
|
d.dismiss();
|
||||||
|
});
|
||||||
|
});
|
||||||
dialog.show();
|
dialog.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,36 +283,55 @@ public class ImportBackupActivity extends ActionBarActivity implements ServiceCo
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAccountAlreadySetup() {
|
public void onAccountAlreadySetup() {
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(
|
||||||
setLoadingState(false);
|
() -> {
|
||||||
Snackbar.make(binding.coordinator, R.string.account_already_setup, Snackbar.LENGTH_LONG).show();
|
setLoadingState(false);
|
||||||
});
|
Snackbar.make(
|
||||||
|
binding.coordinator,
|
||||||
|
R.string.account_already_setup,
|
||||||
|
Snackbar.LENGTH_LONG)
|
||||||
|
.show();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBackupRestored() {
|
public void onBackupRestored() {
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(
|
||||||
Intent intent = new Intent(this, ConversationActivity.class);
|
() -> {
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
Intent intent = new Intent(this, ConversationActivity.class);
|
||||||
startActivity(intent);
|
intent.addFlags(
|
||||||
finish();
|
Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||||
});
|
| Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
|
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||||
|
startActivity(intent);
|
||||||
|
finish();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBackupDecryptionFailed() {
|
public void onBackupDecryptionFailed() {
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(
|
||||||
setLoadingState(false);
|
() -> {
|
||||||
Snackbar.make(binding.coordinator, R.string.unable_to_decrypt_backup, Snackbar.LENGTH_LONG).show();
|
setLoadingState(false);
|
||||||
});
|
Snackbar.make(
|
||||||
|
binding.coordinator,
|
||||||
|
R.string.unable_to_decrypt_backup,
|
||||||
|
Snackbar.LENGTH_LONG)
|
||||||
|
.show();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBackupRestoreFailed() {
|
public void onBackupRestoreFailed() {
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(
|
||||||
setLoadingState(false);
|
() -> {
|
||||||
Snackbar.make(binding.coordinator, R.string.unable_to_restore_backup, Snackbar.LENGTH_LONG).show();
|
setLoadingState(false);
|
||||||
});
|
Snackbar.make(
|
||||||
|
binding.coordinator,
|
||||||
|
R.string.unable_to_restore_backup,
|
||||||
|
Snackbar.LENGTH_LONG)
|
||||||
|
.show();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -238,6 +348,7 @@ public class ImportBackupActivity extends ActionBarActivity implements ServiceCo
|
||||||
intent.setType("*/*");
|
intent.setType("*/*");
|
||||||
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, false);
|
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, false);
|
||||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||||
startActivityForResult(Intent.createChooser(intent, getString(R.string.open_backup)), 0xbac);
|
startActivityForResult(
|
||||||
|
Intent.createChooser(intent, getString(R.string.open_backup)), 0xbac);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,4 +3,9 @@
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
||||||
<uses-permission android:name="android.permission.READ_PROFILE" />
|
<uses-permission android:name="android.permission.READ_PROFILE" />
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED"/>
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
|
@ -769,8 +769,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
|
||||||
}
|
}
|
||||||
|
|
||||||
private void askForContactsPermissions() {
|
private void askForContactsPermissions() {
|
||||||
if (QuickConversationsService.isContactListIntegration(this)
|
if (QuickConversationsService.isContactListIntegration(this)) {
|
||||||
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
||||||
if (checkSelfPermission(Manifest.permission.READ_CONTACTS)
|
if (checkSelfPermission(Manifest.permission.READ_CONTACTS)
|
||||||
!= PackageManager.PERMISSION_GRANTED) {
|
!= PackageManager.PERMISSION_GRANTED) {
|
||||||
if (mRequestedContactsPermission.compareAndSet(false, true)) {
|
if (mRequestedContactsPermission.compareAndSet(false, true)) {
|
||||||
|
|
Loading…
Reference in a new issue