mirror of https://github.com/tasks/tasks
Remove missed call functionality
This feature violates impending Google Play Developer policy change: https://android-developers.googleblog.com/2018/10/providing-safe-and-secure-experience.htmlpull/757/head
parent
bffd683e03
commit
4aab081f6c
@ -1,265 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* <p>See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.calls;
|
||||
|
||||
import static org.tasks.time.DateTimeUtils.currentTimeMillis;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ContentUris;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.net.Uri;
|
||||
import android.provider.CallLog.Calls;
|
||||
import android.provider.ContactsContract;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.text.TextUtils;
|
||||
import com.todoroo.andlib.utility.AndroidUtilities;
|
||||
import com.todoroo.andlib.utility.DateUtilities;
|
||||
import java.io.InputStream;
|
||||
import javax.inject.Inject;
|
||||
import org.tasks.R;
|
||||
import org.tasks.injection.BroadcastComponent;
|
||||
import org.tasks.injection.ForApplication;
|
||||
import org.tasks.injection.InjectingBroadcastReceiver;
|
||||
import org.tasks.notifications.NotificationManager;
|
||||
import org.tasks.preferences.PermissionChecker;
|
||||
import org.tasks.preferences.Preferences;
|
||||
import org.tasks.reminders.MissedCallActivity;
|
||||
import timber.log.Timber;
|
||||
|
||||
public class PhoneStateChangedReceiver extends InjectingBroadcastReceiver {
|
||||
|
||||
private static final String PREF_LAST_INCOMING_NUMBER = "last_incoming_number";
|
||||
|
||||
private static final long WAIT_BEFORE_READ_LOG = 3000L;
|
||||
|
||||
@Inject Preferences preferences;
|
||||
@Inject NotificationManager notificationManager;
|
||||
@Inject PermissionChecker permissionChecker;
|
||||
@Inject @ForApplication Context context;
|
||||
|
||||
@Override
|
||||
public void onReceive(final Context context, Intent intent) {
|
||||
super.onReceive(context, intent);
|
||||
|
||||
if (!intent.getAction().equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!preferences.fieldMissedPhoneCalls()) {
|
||||
preferences.clear(PREF_LAST_INCOMING_NUMBER);
|
||||
return;
|
||||
}
|
||||
|
||||
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
|
||||
|
||||
if (TelephonyManager.EXTRA_STATE_RINGING.equals(state)) {
|
||||
String number = digitsOnly(intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER));
|
||||
if (TextUtils.isEmpty(number)) {
|
||||
return;
|
||||
}
|
||||
|
||||
preferences.setString(PREF_LAST_INCOMING_NUMBER, number);
|
||||
} else if (TelephonyManager.EXTRA_STATE_IDLE.equals(state)) {
|
||||
final String lastNumber = preferences.getStringValue(PREF_LAST_INCOMING_NUMBER);
|
||||
if (TextUtils.isEmpty(lastNumber)) {
|
||||
return;
|
||||
}
|
||||
|
||||
preferences.clear(PREF_LAST_INCOMING_NUMBER);
|
||||
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
AndroidUtilities.sleepDeep(WAIT_BEFORE_READ_LOG);
|
||||
Cursor calls;
|
||||
try {
|
||||
calls = getMissedCalls();
|
||||
} catch (Exception e) { // Sometimes database is locked, retry once
|
||||
Timber.e(e);
|
||||
AndroidUtilities.sleepDeep(300L);
|
||||
try {
|
||||
calls = getMissedCalls();
|
||||
} catch (Exception e2) {
|
||||
Timber.e(e2);
|
||||
calls = null;
|
||||
}
|
||||
}
|
||||
try {
|
||||
if (calls == null) {
|
||||
return;
|
||||
}
|
||||
if (calls.moveToFirst()) {
|
||||
int numberIndex = calls.getColumnIndex(Calls.NUMBER);
|
||||
String number = calls.getString(numberIndex);
|
||||
|
||||
// Sanity check for phone number match
|
||||
// in case the phone logs haven't updated for some reaosn
|
||||
if (!lastNumber.equals(digitsOnly(number))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If a lot of time has passed since the most recent missed call, ignore
|
||||
// It could be the same person calling you back before you call them back,
|
||||
// but if you answer this time, the missed call will still be in the database
|
||||
// and will be processed again.
|
||||
int dateIndex = calls.getColumnIndex(Calls.DATE);
|
||||
long date = calls.getLong(dateIndex);
|
||||
if (DateUtilities.now() - date > 2 * DateUtilities.ONE_MINUTE) {
|
||||
return;
|
||||
}
|
||||
|
||||
int nameIndex = calls.getColumnIndex(Calls.CACHED_NAME);
|
||||
String name = calls.getString(nameIndex);
|
||||
|
||||
long contactId = getContactIdFromNumber(context, number);
|
||||
|
||||
triggerMissedCallNotification(name, number, contactId);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Timber.e(e);
|
||||
} finally {
|
||||
if (calls != null) {
|
||||
calls.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
private Cursor getMissedCalls() {
|
||||
if (permissionChecker.canAccessMissedCallPermissions()) {
|
||||
//noinspection MissingPermission
|
||||
return context
|
||||
.getContentResolver()
|
||||
.query(
|
||||
Calls.CONTENT_URI,
|
||||
new String[] {Calls.NUMBER, Calls.DATE, Calls.CACHED_NAME},
|
||||
Calls.TYPE + " = ? AND " + Calls.NEW + " = ?",
|
||||
new String[] {Integer.toString(Calls.MISSED_TYPE), "1"},
|
||||
Calls.DATE + " DESC");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void inject(BroadcastComponent component) {
|
||||
component.inject(this);
|
||||
}
|
||||
|
||||
private String digitsOnly(String number) {
|
||||
if (number == null) {
|
||||
return "";
|
||||
}
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0; i < number.length(); i++) {
|
||||
char c = number.charAt(i);
|
||||
if (Character.isDigit(c)) {
|
||||
builder.append(c);
|
||||
}
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private long getContactIdFromNumber(Context context, String number) {
|
||||
Uri contactUri =
|
||||
Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
|
||||
Cursor c =
|
||||
context
|
||||
.getContentResolver()
|
||||
.query(contactUri, new String[] {ContactsContract.PhoneLookup._ID}, null, null, null);
|
||||
|
||||
try {
|
||||
if (c.moveToFirst()) {
|
||||
return c.getLong(c.getColumnIndex(ContactsContract.PhoneLookup._ID));
|
||||
}
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private void triggerMissedCallNotification(
|
||||
final String name, final String number, long contactId) {
|
||||
final String title =
|
||||
context.getString(R.string.missed_call, TextUtils.isEmpty(name) ? number : name);
|
||||
|
||||
Intent missedCallDialog = new Intent(context, MissedCallActivity.class);
|
||||
missedCallDialog.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
missedCallDialog.putExtra(MissedCallActivity.EXTRA_NUMBER, number);
|
||||
missedCallDialog.putExtra(MissedCallActivity.EXTRA_NAME, name);
|
||||
missedCallDialog.putExtra(MissedCallActivity.EXTRA_TITLE, title);
|
||||
|
||||
NotificationCompat.Builder builder =
|
||||
new NotificationCompat.Builder(context, NotificationManager.NOTIFICATION_CHANNEL_CALLS)
|
||||
.setTicker(title)
|
||||
.setContentTitle(title)
|
||||
.setContentText(context.getString(R.string.app_name))
|
||||
.setWhen(currentTimeMillis())
|
||||
.setShowWhen(true)
|
||||
.setSmallIcon(R.drawable.ic_check_white_24dp)
|
||||
.setContentIntent(
|
||||
PendingIntent.getActivity(
|
||||
context,
|
||||
missedCallDialog.hashCode(),
|
||||
missedCallDialog,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT));
|
||||
|
||||
Bitmap contactImage = getContactImage(contactId);
|
||||
if (contactImage != null) {
|
||||
builder.setLargeIcon(contactImage);
|
||||
}
|
||||
|
||||
Intent callNow = new Intent(context, MissedCallActivity.class);
|
||||
callNow.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
callNow.putExtra(MissedCallActivity.EXTRA_NUMBER, number);
|
||||
callNow.putExtra(MissedCallActivity.EXTRA_NAME, name);
|
||||
callNow.putExtra(MissedCallActivity.EXTRA_TITLE, title);
|
||||
callNow.putExtra(MissedCallActivity.EXTRA_CALL_NOW, true);
|
||||
|
||||
Intent callLater = new Intent(context, MissedCallActivity.class);
|
||||
callLater.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
callLater.putExtra(MissedCallActivity.EXTRA_NUMBER, number);
|
||||
callLater.putExtra(MissedCallActivity.EXTRA_NAME, name);
|
||||
callLater.putExtra(MissedCallActivity.EXTRA_TITLE, title);
|
||||
callLater.putExtra(MissedCallActivity.EXTRA_CALL_LATER, true);
|
||||
builder
|
||||
.addAction(
|
||||
R.drawable.ic_phone_white_24dp,
|
||||
context.getString(R.string.MCA_return_call),
|
||||
PendingIntent.getActivity(
|
||||
context, callNow.hashCode(), callNow, PendingIntent.FLAG_UPDATE_CURRENT))
|
||||
.addAction(
|
||||
R.drawable.ic_add_white_24dp,
|
||||
context.getString(R.string.MCA_add_task),
|
||||
PendingIntent.getActivity(
|
||||
context, callLater.hashCode(), callLater, PendingIntent.FLAG_UPDATE_CURRENT));
|
||||
|
||||
notificationManager.notify(number.hashCode(), builder, true, false, false);
|
||||
}
|
||||
|
||||
private Bitmap getContactImage(long contactId) {
|
||||
Bitmap b = null;
|
||||
if (contactId >= 0) {
|
||||
Uri uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, contactId);
|
||||
InputStream input =
|
||||
ContactsContract.Contacts.openContactPhotoInputStream(context.getContentResolver(), uri);
|
||||
try {
|
||||
b = BitmapFactory.decodeStream(input);
|
||||
} catch (OutOfMemoryError e) {
|
||||
Timber.e(e);
|
||||
}
|
||||
}
|
||||
return b;
|
||||
}
|
||||
}
|
@ -1,104 +0,0 @@
|
||||
package org.tasks.reminders;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.text.TextUtils;
|
||||
import com.todoroo.astrid.data.Task;
|
||||
import com.todoroo.astrid.service.TaskCreator;
|
||||
import javax.inject.Inject;
|
||||
import org.tasks.R;
|
||||
import org.tasks.injection.ActivityComponent;
|
||||
import org.tasks.injection.InjectingAppCompatActivity;
|
||||
import org.tasks.intents.TaskIntents;
|
||||
import org.tasks.notifications.NotificationManager;
|
||||
|
||||
public class MissedCallActivity extends InjectingAppCompatActivity
|
||||
implements MissedCallDialog.MissedCallHandler {
|
||||
|
||||
public static final String EXTRA_NUMBER = "number"; // $NON-NLS-1$
|
||||
public static final String EXTRA_NAME = "name"; // $NON-NLS-1$
|
||||
public static final String EXTRA_TITLE = "extra_title";
|
||||
public static final String EXTRA_CALL_NOW = "extra_call_now";
|
||||
public static final String EXTRA_CALL_LATER = "extra_call_later";
|
||||
private static final String FRAG_TAG_MISSED_CALL_FRAGMENT = "frag_tag_missed_call_fragment";
|
||||
@Inject NotificationManager notificationManager;
|
||||
@Inject TaskCreator taskCreator;
|
||||
|
||||
private String name;
|
||||
private String number;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setup(getIntent());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inject(ActivityComponent component) {
|
||||
component.inject(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
|
||||
setup(intent);
|
||||
}
|
||||
|
||||
private void setup(Intent intent) {
|
||||
name = intent.getStringExtra(EXTRA_NAME);
|
||||
number = intent.getStringExtra(EXTRA_NUMBER);
|
||||
|
||||
if (intent.getBooleanExtra(EXTRA_CALL_NOW, false)) {
|
||||
callNow();
|
||||
} else if (intent.getBooleanExtra(EXTRA_CALL_LATER, false)) {
|
||||
callLater();
|
||||
} else {
|
||||
FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
MissedCallDialog fragment =
|
||||
(MissedCallDialog) fragmentManager.findFragmentByTag(FRAG_TAG_MISSED_CALL_FRAGMENT);
|
||||
if (fragment == null) {
|
||||
fragment = new MissedCallDialog();
|
||||
fragment.show(fragmentManager, FRAG_TAG_MISSED_CALL_FRAGMENT);
|
||||
}
|
||||
fragment.setTitle(intent.getStringExtra(EXTRA_TITLE));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dismiss() {
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void callNow() {
|
||||
Intent call = new Intent(Intent.ACTION_VIEW);
|
||||
call.setData(Uri.parse("tel:" + number)); // $NON-NLS-1$
|
||||
startActivity(call);
|
||||
cancelNotificationAndFinish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void callLater() {
|
||||
String title =
|
||||
TextUtils.isEmpty(name)
|
||||
? getString(R.string.MCA_task_title_no_name, number)
|
||||
: getString(R.string.MCA_task_title_name, name, number);
|
||||
Task task = taskCreator.basicQuickAddTask(title);
|
||||
TaskIntents.getEditTaskStack(this, null, task.getId()).startActivities();
|
||||
cancelNotificationAndFinish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ignore() {
|
||||
cancelNotificationAndFinish();
|
||||
}
|
||||
|
||||
private void cancelNotificationAndFinish() {
|
||||
notificationManager.cancel(number.hashCode());
|
||||
finish();
|
||||
}
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
package org.tasks.reminders;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import java.util.List;
|
||||
import javax.inject.Inject;
|
||||
import org.tasks.R;
|
||||
import org.tasks.dialogs.DialogBuilder;
|
||||
import org.tasks.injection.DialogFragmentComponent;
|
||||
import org.tasks.injection.InjectingDialogFragment;
|
||||
|
||||
public class MissedCallDialog extends InjectingDialogFragment {
|
||||
|
||||
@Inject DialogBuilder dialogBuilder;
|
||||
private String title;
|
||||
private MissedCallHandler handler;
|
||||
|
||||
@Override
|
||||
protected void inject(DialogFragmentComponent component) {
|
||||
component.inject(this);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
List<String> actions =
|
||||
asList(
|
||||
getString(R.string.MCA_return_call),
|
||||
getString(R.string.MCA_add_task),
|
||||
getString(R.string.MCA_ignore));
|
||||
|
||||
handler = (MissedCallHandler) getActivity();
|
||||
|
||||
return dialogBuilder
|
||||
.newDialog()
|
||||
.setTitle(title)
|
||||
.setItems(
|
||||
actions,
|
||||
(dialog, which) -> {
|
||||
switch (which) {
|
||||
case 0:
|
||||
handler.callNow();
|
||||
break;
|
||||
case 1:
|
||||
handler.callLater();
|
||||
break;
|
||||
default:
|
||||
handler.ignore();
|
||||
break;
|
||||
}
|
||||
})
|
||||
.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDismiss(DialogInterface dialog) {
|
||||
handler.dismiss();
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
Dialog dialog = getDialog();
|
||||
if (dialog != null) {
|
||||
dialog.setTitle(title);
|
||||
}
|
||||
}
|
||||
|
||||
public interface MissedCallHandler {
|
||||
|
||||
void callNow();
|
||||
|
||||
void callLater();
|
||||
|
||||
void ignore();
|
||||
|
||||
void dismiss();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue