From 040aca6d7cea88724ad9397b0d5db175ef91616e Mon Sep 17 00:00:00 2001 From: Sam Bosley Date: Fri, 27 Apr 2012 16:16:42 -0700 Subject: [PATCH 01/13] Basic logic for intercepting missed calls --- astrid/AndroidManifest.xml | 8 +++ .../calls/PhoneStateChangedReceiver.java | 56 +++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 astrid/plugin-src/com/todoroo/astrid/calls/PhoneStateChangedReceiver.java diff --git a/astrid/AndroidManifest.xml b/astrid/AndroidManifest.xml index f21d2e1ac..233b37f79 100644 --- a/astrid/AndroidManifest.xml +++ b/astrid/AndroidManifest.xml @@ -32,6 +32,8 @@ + + @@ -198,6 +200,12 @@ + + + + + + diff --git a/astrid/plugin-src/com/todoroo/astrid/calls/PhoneStateChangedReceiver.java b/astrid/plugin-src/com/todoroo/astrid/calls/PhoneStateChangedReceiver.java new file mode 100644 index 000000000..ceacadfa3 --- /dev/null +++ b/astrid/plugin-src/com/todoroo/astrid/calls/PhoneStateChangedReceiver.java @@ -0,0 +1,56 @@ +package com.todoroo.astrid.calls; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.provider.CallLog.Calls; +import android.telephony.TelephonyManager; +import android.text.TextUtils; + +import com.todoroo.andlib.utility.Preferences; + +@SuppressWarnings("nls") +public class PhoneStateChangedReceiver extends BroadcastReceiver { + + private static final String PREF_LAST_INCOMING_NUMBER = "last_incoming_number"; + + @Override + public void onReceive(Context context, Intent intent) { + String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE); + + if (TelephonyManager.EXTRA_STATE_RINGING.equals(state)) { + String number = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER); + System.err.println("Ringing: " + number); + if (TextUtils.isEmpty(number)) + return; + + Preferences.setString(PREF_LAST_INCOMING_NUMBER, number); + } else if (TelephonyManager.EXTRA_STATE_IDLE.equals(state)) { + String lastNumber = Preferences.getStringValue(PREF_LAST_INCOMING_NUMBER); + if (TextUtils.isEmpty(lastNumber)) + return; + + Preferences.clear(PREF_LAST_INCOMING_NUMBER); + Cursor calls = context.getContentResolver().query( + Calls.CONTENT_URI, + null, + Calls.TYPE + " = ? AND " + Calls.NEW + " = ? AND " + Calls.NUMBER + " = ?" , + new String[] { Integer.toString(Calls.MISSED_TYPE), "1", lastNumber }, + Calls.DATE + " DESC" + ); + + try { + if (calls.getCount() > 0) { + calls.moveToFirst(); + System.err.println("Should display notification for number: " + lastNumber); + } + } finally { + calls.close(); + } + } else { + System.err.println("Other state: " + state); + } + } + +} From 29c41bcffe6daab86b8d0b849129c2c59fc5234e Mon Sep 17 00:00:00 2001 From: Sam Bosley Date: Fri, 27 Apr 2012 17:28:53 -0700 Subject: [PATCH 02/13] Displaying the activity in most of its awesomeness --- astrid/AndroidManifest.xml | 4 + .../astrid/calls/MissedCallActivity.java | 47 ++++++++++++ .../calls/PhoneStateChangedReceiver.java | 6 +- astrid/res/layout/astrid_missed_call_view.xml | 74 +++++++++++++++++++ astrid/res/layout/missed_call_activity.xml | 9 +++ astrid/res/values/strings-core.xml | 15 ++++ .../todoroo/astrid/service/ThemeService.java | 15 ++++ 7 files changed, 168 insertions(+), 2 deletions(-) create mode 100644 astrid/plugin-src/com/todoroo/astrid/calls/MissedCallActivity.java create mode 100644 astrid/res/layout/astrid_missed_call_view.xml create mode 100644 astrid/res/layout/missed_call_activity.xml diff --git a/astrid/AndroidManifest.xml b/astrid/AndroidManifest.xml index 233b37f79..b51db00b3 100644 --- a/astrid/AndroidManifest.xml +++ b/astrid/AndroidManifest.xml @@ -278,6 +278,10 @@ + + + diff --git a/astrid/plugin-src/com/todoroo/astrid/calls/MissedCallActivity.java b/astrid/plugin-src/com/todoroo/astrid/calls/MissedCallActivity.java new file mode 100644 index 000000000..11be3fee3 --- /dev/null +++ b/astrid/plugin-src/com/todoroo/astrid/calls/MissedCallActivity.java @@ -0,0 +1,47 @@ +package com.todoroo.astrid.calls; + +import android.app.Activity; +import android.content.res.Resources; +import android.os.Bundle; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.TextView; + +import com.timsu.astrid.R; +import com.todoroo.andlib.utility.AndroidUtilities; +import com.todoroo.astrid.service.ThemeService; + +public class MissedCallActivity extends Activity { + + public static final String EXTRA_NUMBER = "number"; //$NON-NLS-1$ + + private final OnClickListener dismissListener = new OnClickListener() { + @Override + public void onClick(View v) { + finish(); + AndroidUtilities.callOverridePendingTransition(MissedCallActivity.this, 0, android.R.anim.fade_out); + } + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.missed_call_activity); + int color = ThemeService.getThemeColor(); + + TextView returnCallButton = (TextView) findViewById(R.id.call_return); + TextView addTaskButton = (TextView) findViewById(R.id.call_add); + TextView ignoreButton = (TextView) findViewById(R.id.call_ignore); + View dismissView = findViewById(R.id.dismiss); + + Resources r = getResources(); + returnCallButton.setBackgroundColor(r.getColor(color)); + addTaskButton.setBackgroundColor(r.getColor(color)); + + ignoreButton.setOnClickListener(dismissListener); + dismissView.setOnClickListener(dismissListener); + + System.err.println("Should display notification for number: " + getIntent().getStringExtra(EXTRA_NUMBER)); + } +} diff --git a/astrid/plugin-src/com/todoroo/astrid/calls/PhoneStateChangedReceiver.java b/astrid/plugin-src/com/todoroo/astrid/calls/PhoneStateChangedReceiver.java index ceacadfa3..2930bfc71 100644 --- a/astrid/plugin-src/com/todoroo/astrid/calls/PhoneStateChangedReceiver.java +++ b/astrid/plugin-src/com/todoroo/astrid/calls/PhoneStateChangedReceiver.java @@ -42,8 +42,10 @@ public class PhoneStateChangedReceiver extends BroadcastReceiver { try { if (calls.getCount() > 0) { - calls.moveToFirst(); - System.err.println("Should display notification for number: " + lastNumber); + Intent missedCallIntent = new Intent(context, MissedCallActivity.class); + missedCallIntent.putExtra(MissedCallActivity.EXTRA_NUMBER, lastNumber); + missedCallIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(missedCallIntent); } } finally { calls.close(); diff --git a/astrid/res/layout/astrid_missed_call_view.xml b/astrid/res/layout/astrid_missed_call_view.xml new file mode 100644 index 000000000..ec29b3c5f --- /dev/null +++ b/astrid/res/layout/astrid_missed_call_view.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/astrid/res/layout/missed_call_activity.xml b/astrid/res/layout/missed_call_activity.xml new file mode 100644 index 000000000..44a54f4b3 --- /dev/null +++ b/astrid/res/layout/missed_call_activity.xml @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/astrid/res/values/strings-core.xml b/astrid/res/values/strings-core.xml index 86e6ec114..4adc2da57 100644 --- a/astrid/res/values/strings-core.xml +++ b/astrid/res/values/strings-core.xml @@ -463,6 +463,21 @@ I Disagree + + + + Missed call! + + + Call back + + + Add to task list + + + Ignore + + diff --git a/astrid/src/com/todoroo/astrid/service/ThemeService.java b/astrid/src/com/todoroo/astrid/service/ThemeService.java index 127b1d5f1..4211aeb8f 100644 --- a/astrid/src/com/todoroo/astrid/service/ThemeService.java +++ b/astrid/src/com/todoroo/astrid/service/ThemeService.java @@ -65,6 +65,21 @@ public class ThemeService { return R.style.Theme_White_Blue; } + public static int getThemeColor() { + int theme = getTheme(); + switch(theme) { + case R.style.Theme: + case R.style.Theme_Transparent: + return R.color.blue_theme_color; + case R.style.Theme_White: + case R.style.Theme_TransparentWhite: + return R.color.red_theme_color; + case R.style.Theme_White_Blue: + default: + return R.color.dark_blue_theme_color; + } + } + public static int getEditDialogTheme() { int themeSetting = ThemeService.getTheme(); int theme; From e19fa0819c7e64c143a986db4cde07cacf4d73d5 Mon Sep 17 00:00:00 2001 From: Sam Bosley Date: Fri, 27 Apr 2012 18:02:02 -0700 Subject: [PATCH 03/13] More awesomeness. All that's left is the snooze scheduling --- astrid/AndroidManifest.xml | 1 + .../astrid/calls/MissedCallActivity.java | 56 ++++++++++++++++--- .../calls/PhoneStateChangedReceiver.java | 6 ++ astrid/res/layout/astrid_missed_call_view.xml | 4 +- astrid/res/values/strings-core.xml | 11 +++- 5 files changed, 66 insertions(+), 12 deletions(-) diff --git a/astrid/AndroidManifest.xml b/astrid/AndroidManifest.xml index b51db00b3..d2098a98e 100644 --- a/astrid/AndroidManifest.xml +++ b/astrid/AndroidManifest.xml @@ -34,6 +34,7 @@ + diff --git a/astrid/plugin-src/com/todoroo/astrid/calls/MissedCallActivity.java b/astrid/plugin-src/com/todoroo/astrid/calls/MissedCallActivity.java index 11be3fee3..fd1844ec4 100644 --- a/astrid/plugin-src/com/todoroo/astrid/calls/MissedCallActivity.java +++ b/astrid/plugin-src/com/todoroo/astrid/calls/MissedCallActivity.java @@ -1,8 +1,11 @@ package com.todoroo.astrid.calls; import android.app.Activity; +import android.content.Intent; import android.content.res.Resources; +import android.net.Uri; import android.os.Bundle; +import android.text.TextUtils; import android.view.View; import android.view.View.OnClickListener; import android.widget.TextView; @@ -14,6 +17,7 @@ import com.todoroo.astrid.service.ThemeService; public class MissedCallActivity extends Activity { public static final String EXTRA_NUMBER = "number"; //$NON-NLS-1$ + public static final String EXTRA_NAME = "name"; //$NON-NLS-1$ private final OnClickListener dismissListener = new OnClickListener() { @Override @@ -23,25 +27,63 @@ public class MissedCallActivity extends Activity { } }; + private String name; + private String number; + + private TextView returnCallButton; + private TextView callLaterButton; + private TextView ignoreButton; + private View dismissButton; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.missed_call_activity); + + Intent intent = getIntent(); + + name = intent.getStringExtra(EXTRA_NAME); + number = intent.getStringExtra(EXTRA_NUMBER); + int color = ThemeService.getThemeColor(); - TextView returnCallButton = (TextView) findViewById(R.id.call_return); - TextView addTaskButton = (TextView) findViewById(R.id.call_add); - TextView ignoreButton = (TextView) findViewById(R.id.call_ignore); - View dismissView = findViewById(R.id.dismiss); + returnCallButton = (TextView) findViewById(R.id.call_now); + callLaterButton = (TextView) findViewById(R.id.call_later); + ignoreButton = (TextView) findViewById(R.id.call_ignore); + dismissButton = findViewById(R.id.dismiss); Resources r = getResources(); returnCallButton.setBackgroundColor(r.getColor(color)); - addTaskButton.setBackgroundColor(r.getColor(color)); + callLaterButton.setBackgroundColor(r.getColor(color)); + + addListeners(); + String dialog; + + if (TextUtils.isEmpty(name)) { + dialog = getString(R.string.MCA_dialog_without_name, number); + } else { + dialog = getString(R.string.MCA_dialog_with_name, name); + } + + TextView dialogView = (TextView) findViewById(R.id.reminder_message); + dialogView.setText(dialog); + } + + private void addListeners() { ignoreButton.setOnClickListener(dismissListener); - dismissView.setOnClickListener(dismissListener); + dismissButton.setOnClickListener(dismissListener); + + returnCallButton.setOnClickListener(new OnClickListener() { - System.err.println("Should display notification for number: " + getIntent().getStringExtra(EXTRA_NUMBER)); + @Override + public void onClick(View v) { + Intent call = new Intent(Intent.ACTION_CALL); + call.setData(Uri.parse("tel:" + number)); //$NON-NLS-1$ + startActivity(call); + finish(); + } + }); } } diff --git a/astrid/plugin-src/com/todoroo/astrid/calls/PhoneStateChangedReceiver.java b/astrid/plugin-src/com/todoroo/astrid/calls/PhoneStateChangedReceiver.java index 2930bfc71..5deaf6737 100644 --- a/astrid/plugin-src/com/todoroo/astrid/calls/PhoneStateChangedReceiver.java +++ b/astrid/plugin-src/com/todoroo/astrid/calls/PhoneStateChangedReceiver.java @@ -42,8 +42,14 @@ public class PhoneStateChangedReceiver extends BroadcastReceiver { try { if (calls.getCount() > 0) { + calls.moveToFirst(); + int nameIndex = calls.getColumnIndex(Calls.CACHED_NAME); + String name = ""; + if (nameIndex > -1) + name = calls.getString(nameIndex); Intent missedCallIntent = new Intent(context, MissedCallActivity.class); missedCallIntent.putExtra(MissedCallActivity.EXTRA_NUMBER, lastNumber); + missedCallIntent.putExtra(MissedCallActivity.EXTRA_NAME, name); missedCallIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(missedCallIntent); } diff --git a/astrid/res/layout/astrid_missed_call_view.xml b/astrid/res/layout/astrid_missed_call_view.xml index ec29b3c5f..bbd6570ae 100644 --- a/astrid/res/layout/astrid_missed_call_view.xml +++ b/astrid/res/layout/astrid_missed_call_view.xml @@ -37,7 +37,7 @@ Missed call! - Call back + Call now - Add to task list + Call later Ignore - + + + %s just called you! + + + Someone just called you from %s. From b772c79bf9985277f53b330f6bb3d9db632f051a Mon Sep 17 00:00:00 2001 From: Sam Bosley Date: Mon, 30 Apr 2012 13:16:17 -0700 Subject: [PATCH 04/13] More polish to missed call dialog, preference to activate/deactivate: --- .../astrid/calls/MissedCallActivity.java | 65 ++++++++++++++++++- .../calls/PhoneStateChangedReceiver.java | 6 ++ astrid/res/values/keys.xml | 3 + astrid/res/values/strings-core.xml | 18 +++++ astrid/res/xml/preferences_labs.xml | 4 ++ .../astrid/utility/AstridPreferences.java | 1 + 6 files changed, 96 insertions(+), 1 deletion(-) diff --git a/astrid/plugin-src/com/todoroo/astrid/calls/MissedCallActivity.java b/astrid/plugin-src/com/todoroo/astrid/calls/MissedCallActivity.java index fd1844ec4..32a302334 100644 --- a/astrid/plugin-src/com/todoroo/astrid/calls/MissedCallActivity.java +++ b/astrid/plugin-src/com/todoroo/astrid/calls/MissedCallActivity.java @@ -1,6 +1,10 @@ package com.todoroo.astrid.calls; +import java.util.Date; + import android.app.Activity; +import android.app.AlertDialog; +import android.content.DialogInterface; import android.content.Intent; import android.content.res.Resources; import android.net.Uri; @@ -12,6 +16,10 @@ import android.widget.TextView; import com.timsu.astrid.R; import com.todoroo.andlib.utility.AndroidUtilities; +import com.todoroo.andlib.utility.DialogUtilities; +import com.todoroo.andlib.utility.Preferences; +import com.todoroo.astrid.reminders.NotificationFragment.SnoozeDialog; +import com.todoroo.astrid.reminders.SnoozeCallback; import com.todoroo.astrid.service.ThemeService; public class MissedCallActivity extends Activity { @@ -19,6 +27,8 @@ public class MissedCallActivity extends Activity { public static final String EXTRA_NUMBER = "number"; //$NON-NLS-1$ public static final String EXTRA_NAME = "name"; //$NON-NLS-1$ + private static final String PREF_IGNORE_PRESSES = "missedCallsIgnored"; + private final OnClickListener dismissListener = new OnClickListener() { @Override public void onClick(View v) { @@ -27,6 +37,39 @@ public class MissedCallActivity extends Activity { } }; + private final OnClickListener ignoreListener = new OnClickListener() { + @Override + public void onClick(final View v) { + // Check for number of ignore presses + int ignorePresses = Preferences.getInt(PREF_IGNORE_PRESSES, 0); + ignorePresses++; + if (ignorePresses % 3 == 0) { + DialogUtilities.okCancelCustomDialog(MissedCallActivity.this, + getString(R.string.MCA_ignore_title), + getString(R.string.MCA_ignore_body), + R.string.MCA_ignore_all, + R.string.MCA_ignore_this, + 0, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + Preferences.setBoolean(R.string.p_field_missed_calls, false); + dismissListener.onClick(v); + } + }, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dismissListener.onClick(v); + } + }); + } else { + dismissListener.onClick(v); + } + Preferences.setInt(PREF_IGNORE_PRESSES, ignorePresses); + } + }; + private String name; private String number; @@ -72,7 +115,7 @@ public class MissedCallActivity extends Activity { } private void addListeners() { - ignoreButton.setOnClickListener(dismissListener); + ignoreButton.setOnClickListener(ignoreListener); dismissButton.setOnClickListener(dismissListener); returnCallButton.setOnClickListener(new OnClickListener() { @@ -85,5 +128,25 @@ public class MissedCallActivity extends Activity { finish(); } }); + + callLaterButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + SnoozeDialog sd = new SnoozeDialog(MissedCallActivity.this, new SnoozeCallback() { + @Override + public void snoozeForTime(long time) { + // Create task with due time 'time' + System.err.println("Should create a task for: " + new Date(time)); + finish(); + } + }); + new AlertDialog.Builder(MissedCallActivity.this) + .setTitle(R.string.rmd_NoA_snooze) + .setView(sd) + .setPositiveButton(android.R.string.ok, sd) + .setNegativeButton(android.R.string.cancel, null) + .show().setOwnerActivity(MissedCallActivity.this); + } + }); } } diff --git a/astrid/plugin-src/com/todoroo/astrid/calls/PhoneStateChangedReceiver.java b/astrid/plugin-src/com/todoroo/astrid/calls/PhoneStateChangedReceiver.java index 5deaf6737..e98d26212 100644 --- a/astrid/plugin-src/com/todoroo/astrid/calls/PhoneStateChangedReceiver.java +++ b/astrid/plugin-src/com/todoroo/astrid/calls/PhoneStateChangedReceiver.java @@ -8,6 +8,7 @@ import android.provider.CallLog.Calls; import android.telephony.TelephonyManager; import android.text.TextUtils; +import com.timsu.astrid.R; import com.todoroo.andlib.utility.Preferences; @SuppressWarnings("nls") @@ -17,6 +18,11 @@ public class PhoneStateChangedReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { + if (!Preferences.getBoolean(R.string.p_field_missed_calls, true)) { + Preferences.clear(PREF_LAST_INCOMING_NUMBER); + return; + } + String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE); if (TelephonyManager.EXTRA_STATE_RINGING.equals(state)) { diff --git a/astrid/res/values/keys.xml b/astrid/res/values/keys.xml index 966ba9664..17c6ea356 100644 --- a/astrid/res/values/keys.xml +++ b/astrid/res/values/keys.xml @@ -45,6 +45,9 @@ notif_default_reminder + + + field_missed_calls diff --git a/astrid/res/values/strings-core.xml b/astrid/res/values/strings-core.xml index dcc9c8c91..fde4d98df 100644 --- a/astrid/res/values/strings-core.xml +++ b/astrid/res/values/strings-core.xml @@ -483,6 +483,24 @@ Someone just called you from %s. + + Ignore all missed calls? + + + You\'ve ignored several missed calls. Should Astrid stop asking you about them? + + + Ignore all calls + + + Ignore this call only + + + Field missed calls + + + Astrid will notify you about missed calls and offer to remind you to call back + diff --git a/astrid/res/xml/preferences_labs.xml b/astrid/res/xml/preferences_labs.xml index ac0e07add..e5798c091 100644 --- a/astrid/res/xml/preferences_labs.xml +++ b/astrid/res/xml/preferences_labs.xml @@ -13,4 +13,8 @@ android:key="@string/p_use_contact_picker" android:title="@string/EPr_use_contact_picker" android:summary="@string/EPr_use_contact_picker_desc"/> + diff --git a/astrid/src/com/todoroo/astrid/utility/AstridPreferences.java b/astrid/src/com/todoroo/astrid/utility/AstridPreferences.java index a647ddd73..1bfbce5d8 100644 --- a/astrid/src/com/todoroo/astrid/utility/AstridPreferences.java +++ b/astrid/src/com/todoroo/astrid/utility/AstridPreferences.java @@ -48,6 +48,7 @@ public class AstridPreferences { Preferences.setIfUnset(prefs, editor, r, R.string.p_rmd_default_random_hours, 0); Preferences.setIfUnset(prefs, editor, r, R.string.p_fontSize, 18); Preferences.setIfUnset(prefs, editor, r, R.string.p_showNotes, false); + Preferences.setIfUnset(prefs, editor, r, R.string.p_field_missed_calls, true); boolean swipeEnabled = (ABChooser.readChoiceForTest(ABTests.AB_TEST_SWIPE_ENABLED_KEY) == 1); Preferences.setIfUnset(prefs, editor, r, R.string.p_swipe_lists_performance_key, swipeEnabled ? 3 : 0); From 0e613f9017f2160100800138314f52c02955a706 Mon Sep 17 00:00:00 2001 From: Sam Bosley Date: Mon, 30 Apr 2012 13:36:24 -0700 Subject: [PATCH 05/13] Wire up call later button to create tasks with the appropriate due time --- .../astrid/calls/MissedCallActivity.java | 28 +++++++++++++++---- .../calls/PhoneStateChangedReceiver.java | 13 +++++++-- astrid/res/values/strings-core.xml | 16 ++++++++--- 3 files changed, 45 insertions(+), 12 deletions(-) diff --git a/astrid/plugin-src/com/todoroo/astrid/calls/MissedCallActivity.java b/astrid/plugin-src/com/todoroo/astrid/calls/MissedCallActivity.java index 32a302334..32fcc6ab9 100644 --- a/astrid/plugin-src/com/todoroo/astrid/calls/MissedCallActivity.java +++ b/astrid/plugin-src/com/todoroo/astrid/calls/MissedCallActivity.java @@ -1,7 +1,5 @@ package com.todoroo.astrid.calls; -import java.util.Date; - import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; @@ -15,19 +13,26 @@ import android.view.View.OnClickListener; import android.widget.TextView; import com.timsu.astrid.R; +import com.todoroo.andlib.service.Autowired; +import com.todoroo.andlib.service.DependencyInjectionService; import com.todoroo.andlib.utility.AndroidUtilities; import com.todoroo.andlib.utility.DialogUtilities; import com.todoroo.andlib.utility.Preferences; +import com.todoroo.astrid.data.Task; import com.todoroo.astrid.reminders.NotificationFragment.SnoozeDialog; import com.todoroo.astrid.reminders.SnoozeCallback; +import com.todoroo.astrid.service.TaskService; import com.todoroo.astrid.service.ThemeService; public class MissedCallActivity extends Activity { 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_TIME = "time"; //$NON-NLS-1$ + + private static final String PREF_IGNORE_PRESSES = "missedCallsIgnored"; //$NON-NLS-1$ - private static final String PREF_IGNORE_PRESSES = "missedCallsIgnored"; + @Autowired private TaskService taskService; private final OnClickListener dismissListener = new OnClickListener() { @Override @@ -72,6 +77,7 @@ public class MissedCallActivity extends Activity { private String name; private String number; + private String timeString; private TextView returnCallButton; private TextView callLaterButton; @@ -81,6 +87,7 @@ public class MissedCallActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + DependencyInjectionService.getInstance().inject(this); setContentView(R.layout.missed_call_activity); @@ -88,6 +95,7 @@ public class MissedCallActivity extends Activity { name = intent.getStringExtra(EXTRA_NAME); number = intent.getStringExtra(EXTRA_NUMBER); + timeString = intent.getStringExtra(EXTRA_TIME); int color = ThemeService.getThemeColor(); @@ -95,6 +103,7 @@ public class MissedCallActivity extends Activity { callLaterButton = (TextView) findViewById(R.id.call_later); ignoreButton = (TextView) findViewById(R.id.call_ignore); dismissButton = findViewById(R.id.dismiss); + ((TextView) findViewById(R.id.reminder_title)).setText(getString(R.string.MCA_title, timeString)); Resources r = getResources(); returnCallButton.setBackgroundColor(r.getColor(color)); @@ -135,8 +144,17 @@ public class MissedCallActivity extends Activity { SnoozeDialog sd = new SnoozeDialog(MissedCallActivity.this, new SnoozeCallback() { @Override public void snoozeForTime(long time) { - // Create task with due time 'time' - System.err.println("Should create a task for: " + new Date(time)); + String title; + if (TextUtils.isEmpty(name)) + title = getString(R.string.MCA_task_title_no_name, number); + else + title = getString(R.string.MCA_task_title_name, name, number); + + Task newTask = new Task(); + newTask.setValue(Task.TITLE, title); + newTask.setValue(Task.DUE_DATE, time); + taskService.save(newTask); + finish(); } }); diff --git a/astrid/plugin-src/com/todoroo/astrid/calls/PhoneStateChangedReceiver.java b/astrid/plugin-src/com/todoroo/astrid/calls/PhoneStateChangedReceiver.java index e98d26212..86d8a59bf 100644 --- a/astrid/plugin-src/com/todoroo/astrid/calls/PhoneStateChangedReceiver.java +++ b/astrid/plugin-src/com/todoroo/astrid/calls/PhoneStateChangedReceiver.java @@ -1,5 +1,7 @@ package com.todoroo.astrid.calls; +import java.util.Date; + import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -9,6 +11,7 @@ import android.telephony.TelephonyManager; import android.text.TextUtils; import com.timsu.astrid.R; +import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.andlib.utility.Preferences; @SuppressWarnings("nls") @@ -50,12 +53,16 @@ public class PhoneStateChangedReceiver extends BroadcastReceiver { if (calls.getCount() > 0) { calls.moveToFirst(); int nameIndex = calls.getColumnIndex(Calls.CACHED_NAME); - String name = ""; - if (nameIndex > -1) - name = calls.getString(nameIndex); + String name = calls.getString(nameIndex); + + int timeIndex = calls.getColumnIndex(Calls.DATE); + long time = calls.getLong(timeIndex); + String timeString = DateUtilities.getTimeString(context, new Date(time)); + Intent missedCallIntent = new Intent(context, MissedCallActivity.class); missedCallIntent.putExtra(MissedCallActivity.EXTRA_NUMBER, lastNumber); missedCallIntent.putExtra(MissedCallActivity.EXTRA_NAME, name); + missedCallIntent.putExtra(MissedCallActivity.EXTRA_TIME, timeString); missedCallIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(missedCallIntent); } diff --git a/astrid/res/values/strings-core.xml b/astrid/res/values/strings-core.xml index fde4d98df..274506811 100644 --- a/astrid/res/values/strings-core.xml +++ b/astrid/res/values/strings-core.xml @@ -465,8 +465,8 @@ - - Missed call! + + Missed call at %s Call now @@ -478,10 +478,10 @@ Ignore - %s just called you! + %s just called. What do you want to do? - Someone just called you from %s. + Someone just called you from %s. What do you want to do? Ignore all missed calls? @@ -500,6 +500,14 @@ Astrid will notify you about missed calls and offer to remind you to call back + + + Call %1$s back at %2$s + + + Call %s back + + From e0a30bb3e31bb751244c6061fb04f217c9119bff Mon Sep 17 00:00:00 2001 From: Sam Bosley Date: Mon, 30 Apr 2012 13:50:14 -0700 Subject: [PATCH 06/13] Use flag_activity_multiple_task to stack missed call notifications --- .../com/todoroo/astrid/calls/PhoneStateChangedReceiver.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/astrid/plugin-src/com/todoroo/astrid/calls/PhoneStateChangedReceiver.java b/astrid/plugin-src/com/todoroo/astrid/calls/PhoneStateChangedReceiver.java index 86d8a59bf..226be8259 100644 --- a/astrid/plugin-src/com/todoroo/astrid/calls/PhoneStateChangedReceiver.java +++ b/astrid/plugin-src/com/todoroo/astrid/calls/PhoneStateChangedReceiver.java @@ -63,7 +63,7 @@ public class PhoneStateChangedReceiver extends BroadcastReceiver { missedCallIntent.putExtra(MissedCallActivity.EXTRA_NUMBER, lastNumber); missedCallIntent.putExtra(MissedCallActivity.EXTRA_NAME, name); missedCallIntent.putExtra(MissedCallActivity.EXTRA_TIME, timeString); - missedCallIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + missedCallIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); context.startActivity(missedCallIntent); } } finally { From a4a53ad1951aae7247d626e942447c83f5c8ba40 Mon Sep 17 00:00:00 2001 From: Sam Bosley Date: Mon, 30 Apr 2012 15:40:14 -0700 Subject: [PATCH 07/13] Fixed bugs when fielding missed calls on real phones --- .../calls/PhoneStateChangedReceiver.java | 39 ++++++++++++++++--- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/astrid/plugin-src/com/todoroo/astrid/calls/PhoneStateChangedReceiver.java b/astrid/plugin-src/com/todoroo/astrid/calls/PhoneStateChangedReceiver.java index 226be8259..9d686bb13 100644 --- a/astrid/plugin-src/com/todoroo/astrid/calls/PhoneStateChangedReceiver.java +++ b/astrid/plugin-src/com/todoroo/astrid/calls/PhoneStateChangedReceiver.java @@ -29,8 +29,7 @@ public class PhoneStateChangedReceiver extends BroadcastReceiver { String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE); if (TelephonyManager.EXTRA_STATE_RINGING.equals(state)) { - String number = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER); - System.err.println("Ringing: " + number); + String number = digitsOnly(intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER)); if (TextUtils.isEmpty(number)) return; @@ -44,14 +43,31 @@ public class PhoneStateChangedReceiver extends BroadcastReceiver { Cursor calls = context.getContentResolver().query( Calls.CONTENT_URI, null, - Calls.TYPE + " = ? AND " + Calls.NEW + " = ? AND " + Calls.NUMBER + " = ?" , - new String[] { Integer.toString(Calls.MISSED_TYPE), "1", lastNumber }, + Calls.TYPE + " = ? AND " + Calls.NEW + " = ?", + new String[] { Integer.toString(Calls.MISSED_TYPE), "1" }, Calls.DATE + " DESC" ); try { if (calls.getCount() > 0) { calls.moveToFirst(); + + int numberIndex = calls.getColumnIndex(Calls.NUMBER); + String number = calls.getString(numberIndex); + + // Check for phone number match + 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); @@ -59,8 +75,9 @@ public class PhoneStateChangedReceiver extends BroadcastReceiver { long time = calls.getLong(timeIndex); String timeString = DateUtilities.getTimeString(context, new Date(time)); + Intent missedCallIntent = new Intent(context, MissedCallActivity.class); - missedCallIntent.putExtra(MissedCallActivity.EXTRA_NUMBER, lastNumber); + missedCallIntent.putExtra(MissedCallActivity.EXTRA_NUMBER, number); missedCallIntent.putExtra(MissedCallActivity.EXTRA_NAME, name); missedCallIntent.putExtra(MissedCallActivity.EXTRA_TIME, timeString); missedCallIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); @@ -70,8 +87,18 @@ public class PhoneStateChangedReceiver extends BroadcastReceiver { calls.close(); } } else { - System.err.println("Other state: " + state); + System.err.println("ASTRID Other state: " + state); + } + } + + private String digitsOnly(String number) { + 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(); } } From 9fe310972f508c5acbf80c76a8df99bacfa59562 Mon Sep 17 00:00:00 2001 From: Sam Bosley Date: Mon, 30 Apr 2012 16:01:28 -0700 Subject: [PATCH 08/13] Don't title the missed call schedule dialog 'snooze' --- .../astrid/calls/MissedCallActivity.java | 18 +++++++++++------- astrid/res/values/strings-core.xml | 3 +++ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/astrid/plugin-src/com/todoroo/astrid/calls/MissedCallActivity.java b/astrid/plugin-src/com/todoroo/astrid/calls/MissedCallActivity.java index 32fcc6ab9..d6f8e0593 100644 --- a/astrid/plugin-src/com/todoroo/astrid/calls/MissedCallActivity.java +++ b/astrid/plugin-src/com/todoroo/astrid/calls/MissedCallActivity.java @@ -141,17 +141,21 @@ public class MissedCallActivity extends Activity { callLaterButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { + final String taskTitle; + String dialogTitle; + if (TextUtils.isEmpty(name)) { + taskTitle = getString(R.string.MCA_task_title_no_name, number); + dialogTitle = getString(R.string.MCA_schedule_dialog_title, number); + } else { + taskTitle = getString(R.string.MCA_task_title_name, name, number); + dialogTitle = getString(R.string.MCA_schedule_dialog_title, name); + } SnoozeDialog sd = new SnoozeDialog(MissedCallActivity.this, new SnoozeCallback() { @Override public void snoozeForTime(long time) { - String title; - if (TextUtils.isEmpty(name)) - title = getString(R.string.MCA_task_title_no_name, number); - else - title = getString(R.string.MCA_task_title_name, name, number); Task newTask = new Task(); - newTask.setValue(Task.TITLE, title); + newTask.setValue(Task.TITLE, taskTitle); newTask.setValue(Task.DUE_DATE, time); taskService.save(newTask); @@ -159,7 +163,7 @@ public class MissedCallActivity extends Activity { } }); new AlertDialog.Builder(MissedCallActivity.this) - .setTitle(R.string.rmd_NoA_snooze) + .setTitle(dialogTitle) .setView(sd) .setPositiveButton(android.R.string.ok, sd) .setNegativeButton(android.R.string.cancel, null) diff --git a/astrid/res/values/strings-core.xml b/astrid/res/values/strings-core.xml index 274506811..137ec0916 100644 --- a/astrid/res/values/strings-core.xml +++ b/astrid/res/values/strings-core.xml @@ -507,6 +507,9 @@ Call %s back + + Call %s back in... + From 29555b08a43dd67551823dd59b00d8dba3c7d42f Mon Sep 17 00:00:00 2001 From: Sam Bosley Date: Mon, 30 Apr 2012 19:23:15 -0700 Subject: [PATCH 09/13] Picture in missed call view, polish close button --- astrid/AndroidManifest.xml | 1 - .../astrid/calls/MissedCallActivity.java | 13 ++++- .../calls/PhoneStateChangedReceiver.java | 46 ++++++++++++++++-- .../res/drawable-hdpi/close_clear_cancel.png | Bin 0 -> 1391 bytes astrid/res/drawable/close_clear_cancel.png | Bin 0 -> 1391 bytes .../res/layout-land/astrid_reminder_view.xml | 2 +- astrid/res/layout/astrid_missed_call_view.xml | 10 +++- astrid/res/layout/astrid_reminder_view.xml | 2 +- .../layout/astrid_reminder_view_portrait.xml | 2 +- astrid/res/layout/tag_settings_activity.xml | 2 +- astrid/res/layout/task_edit_activity.xml | 2 +- astrid/res/values/strings-core.xml | 4 +- .../astrid/activity/TaskEditFragment.java | 2 +- .../astrid/service/UpgradeService.java | 2 + .../astrid/service/abtesting/ABTests.java | 7 ++- .../astrid/utility/AstridPreferences.java | 4 +- 16 files changed, 80 insertions(+), 19 deletions(-) create mode 100644 astrid/res/drawable-hdpi/close_clear_cancel.png create mode 100644 astrid/res/drawable/close_clear_cancel.png diff --git a/astrid/AndroidManifest.xml b/astrid/AndroidManifest.xml index d2098a98e..b51db00b3 100644 --- a/astrid/AndroidManifest.xml +++ b/astrid/AndroidManifest.xml @@ -34,7 +34,6 @@ - diff --git a/astrid/plugin-src/com/todoroo/astrid/calls/MissedCallActivity.java b/astrid/plugin-src/com/todoroo/astrid/calls/MissedCallActivity.java index d6f8e0593..2079e3190 100644 --- a/astrid/plugin-src/com/todoroo/astrid/calls/MissedCallActivity.java +++ b/astrid/plugin-src/com/todoroo/astrid/calls/MissedCallActivity.java @@ -10,6 +10,7 @@ import android.os.Bundle; import android.text.TextUtils; import android.view.View; import android.view.View.OnClickListener; +import android.widget.ImageView; import android.widget.TextView; import com.timsu.astrid.R; @@ -29,6 +30,7 @@ public class MissedCallActivity extends Activity { 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_TIME = "time"; //$NON-NLS-1$ + public static final String EXTRA_PHOTO = "photo"; //$NON-NLS-1$ private static final String PREF_IGNORE_PRESSES = "missedCallsIgnored"; //$NON-NLS-1$ @@ -96,6 +98,7 @@ public class MissedCallActivity extends Activity { name = intent.getStringExtra(EXTRA_NAME); number = intent.getStringExtra(EXTRA_NUMBER); timeString = intent.getStringExtra(EXTRA_TIME); + String picture = intent.getStringExtra(EXTRA_PHOTO); int color = ThemeService.getThemeColor(); @@ -103,7 +106,15 @@ public class MissedCallActivity extends Activity { callLaterButton = (TextView) findViewById(R.id.call_later); ignoreButton = (TextView) findViewById(R.id.call_ignore); dismissButton = findViewById(R.id.dismiss); - ((TextView) findViewById(R.id.reminder_title)).setText(getString(R.string.MCA_title, timeString)); + ((TextView) findViewById(R.id.reminder_title)) + .setText(getString(R.string.MCA_title, + TextUtils.isEmpty(name) ? number : name, timeString)); + + ImageView pictureView = ((ImageView) findViewById(R.id.contact_picture)); + if (TextUtils.isEmpty(picture)) + pictureView.setImageDrawable(getResources().getDrawable(R.drawable.none)); + else + pictureView.setImageURI(Uri.parse(picture)); Resources r = getResources(); returnCallButton.setBackgroundColor(r.getColor(color)); diff --git a/astrid/plugin-src/com/todoroo/astrid/calls/PhoneStateChangedReceiver.java b/astrid/plugin-src/com/todoroo/astrid/calls/PhoneStateChangedReceiver.java index 9d686bb13..7fe0d8c4a 100644 --- a/astrid/plugin-src/com/todoroo/astrid/calls/PhoneStateChangedReceiver.java +++ b/astrid/plugin-src/com/todoroo/astrid/calls/PhoneStateChangedReceiver.java @@ -6,7 +6,9 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.database.Cursor; +import android.net.Uri; import android.provider.CallLog.Calls; +import android.provider.ContactsContract; import android.telephony.TelephonyManager; import android.text.TextUtils; @@ -49,9 +51,7 @@ public class PhoneStateChangedReceiver extends BroadcastReceiver { ); try { - if (calls.getCount() > 0) { - calls.moveToFirst(); - + if (calls.moveToFirst()) { int numberIndex = calls.getColumnIndex(Calls.NUMBER); String number = calls.getString(numberIndex); @@ -65,7 +65,7 @@ public class PhoneStateChangedReceiver extends BroadcastReceiver { // and will be processed again. int dateIndex = calls.getColumnIndex(Calls.DATE); long date = calls.getLong(dateIndex); - if (DateUtilities.now() - date > 2 * DateUtilities.ONE_MINUTE) + if (DateUtilities.now() - date < 2 * DateUtilities.ONE_MINUTE) return; int nameIndex = calls.getColumnIndex(Calls.CACHED_NAME); @@ -75,11 +75,13 @@ public class PhoneStateChangedReceiver extends BroadcastReceiver { long time = calls.getLong(timeIndex); String timeString = DateUtilities.getTimeString(context, new Date(time)); + String photo = getContactPhotoFromNumber(context, number); Intent missedCallIntent = new Intent(context, MissedCallActivity.class); missedCallIntent.putExtra(MissedCallActivity.EXTRA_NUMBER, number); missedCallIntent.putExtra(MissedCallActivity.EXTRA_NAME, name); missedCallIntent.putExtra(MissedCallActivity.EXTRA_TIME, timeString); + missedCallIntent.putExtra(MissedCallActivity.EXTRA_PHOTO, photo); missedCallIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); context.startActivity(missedCallIntent); } @@ -101,4 +103,40 @@ public class PhoneStateChangedReceiver extends BroadcastReceiver { return builder.toString(); } + private String getContactPhotoFromNumber(Context context, String number) { + return getPhotoForContactId(context, getContactIdFromNumber(context, number)); + } + + 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()) { + long id = c.getLong(c.getColumnIndex(ContactsContract.PhoneLookup._ID)); + return id; + } + } finally { + c.close(); + } + return -1; + } + + private String getPhotoForContactId(Context context, long contactId) { + if (contactId < 0) + return ""; + Cursor c = context.getContentResolver().query(ContactsContract.Contacts.CONTENT_FILTER_URI, + new String[] { ContactsContract.Contacts.PHOTO_URI }, + ContactsContract.Contacts._ID + " = ?", new String[] { Long.toString(contactId) }, null); + try { + if (c.moveToFirst()) { + String uri = c.getString(c.getColumnIndex(ContactsContract.Contacts.PHOTO_URI)); + return uri; + } + } finally { + c.close(); + } + return ""; + } + } diff --git a/astrid/res/drawable-hdpi/close_clear_cancel.png b/astrid/res/drawable-hdpi/close_clear_cancel.png new file mode 100644 index 0000000000000000000000000000000000000000..778c7f0812d8d59d7ec939c631119a902e589ee9 GIT binary patch literal 1391 zcmV-#1(5oQP)ngbTigy2`#dwm3%KVlF_q@R2XQu99UR~Y{iNA92xyBdQg3wFtt;Wn+d{~AT70AA z6Rc+}Is%Re;5fdzgwx{dO1BC?0R94b(Z;l{QUe?j2bHF%P1ej_K94Q{$oP!7uH+L= z&scOsc=n@fpeEs~}xje{fNpwX0WNw(R~=TO4a#lsmdu~%jz znValoWc4cmaA5%x+%hea)~RNIBMhKgO1GqS^AGOAhLTILSTZs!91*~z_w|`$>;)|N zTxTBufD7~3%Wcz=Qe}uEW>{M6W3gmpNH`*Z@8C#InT=*T*(G25DgX}=uSA45aIMub zw(W;=%1k74lzm>szA6B~gCvSp`z2b-*FUjqQ(LKgdqRp?p_91(*? z`V{pp=0wr{82hY-eN8|Kf=q>VEe0G6hye!$CvYgQ%(i5nU?11CuLJN9%lyMzt2n7O zQUeO$f(++j)C|r%bY-sad>#ABVdo~A&D>-wZfi+*ZzGoZTfPV%fPzfCzQaC= zBRORzlIdo1C}BTeGc75lYb6MqT&RNZ37n(wwz5=WUyPGX2fKs?;ldpDa@(|})K*@o zG(~OqjRhA%!0G`wEWw&lh>t}_1lzJdoax>g$S%xdKVLI#;vtwYu(@GUCz4pGA2VU9!75dQ8`Dn5!SRmwG zXK2YwtMWK;A?u}{ln&FTm;}5%_yy*F-_^4v#1^92#^)N|zw=5yaP`5jvIV~|bYUKk z^Sg^1IHexAuQT|f{iPY2W-H|t?D^BNLi)e_`1RLbKHp1@ZV&%}>}y~DDg6z^7lFuI ztd^z#001R)MObuXVRU6WV{&C-bY%cCFflPLFflDNF;p=#IyE;sFflDKI65#eL6wV# z0000bbVXQnWMOn=I&E)cX=ZrngbTigy2`#dwm3%KVlF_q@R2XQu99UR~Y{iNA92xyBdQg3wFtt;Wn+d{~AT70AA z6Rc+}Is%Re;5fdzgwx{dO1BC?0R94b(Z;l{QUe?j2bHF%P1ej_K94Q{$oP!7uH+L= z&scOsc=n@fpeEs~}xje{fNpwX0WNw(R~=TO4a#lsmdu~%jz znValoWc4cmaA5%x+%hea)~RNIBMhKgO1GqS^AGOAhLTILSTZs!91*~z_w|`$>;)|N zTxTBufD7~3%Wcz=Qe}uEW>{M6W3gmpNH`*Z@8C#InT=*T*(G25DgX}=uSA45aIMub zw(W;=%1k74lzm>szA6B~gCvSp`z2b-*FUjqQ(LKgdqRp?p_91(*? z`V{pp=0wr{82hY-eN8|Kf=q>VEe0G6hye!$CvYgQ%(i5nU?11CuLJN9%lyMzt2n7O zQUeO$f(++j)C|r%bY-sad>#ABVdo~A&D>-wZfi+*ZzGoZTfPV%fPzfCzQaC= zBRORzlIdo1C}BTeGc75lYb6MqT&RNZ37n(wwz5=WUyPGX2fKs?;ldpDa@(|})K*@o zG(~OqjRhA%!0G`wEWw&lh>t}_1lzJdoax>g$S%xdKVLI#;vtwYu(@GUCz4pGA2VU9!75dQ8`Dn5!SRmwG zXK2YwtMWK;A?u}{ln&FTm;}5%_yy*F-_^4v#1^92#^)N|zw=5yaP`5jvIV~|bYUKk z^Sg^1IHexAuQT|f{iPY2W-H|t?D^BNLi)e_`1RLbKHp1@ZV&%}>}y~DDg6z^7lFuI ztd^z#001R)MObuXVRU6WV{&C-bY%cCFflPLFflDNF;p=#IyE;sFflDKI65#eL6wV# z0000bbVXQnWMOn=I&E)cX=Zr + android:src="@drawable/close_clear_cancel"/>