private void onVoiceReminderStatusChanged(final Preference preference, boolean newValue) {
   try {
     VoiceOutputService.getVoiceOutputInstance();
     if (newValue) VoiceOutputService.getVoiceOutputInstance().checkIsTTSInstalled();
   } catch (VerifyError e) {
     // doesn't work :(
     preference.setEnabled(false);
     Preferences.setBoolean(preference.getKey(), false);
   }
 }
 @Override
 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
   try {
     VoiceOutputService.getVoiceOutputInstance()
         .handleActivityResult(requestCode, resultCode, data);
   } catch (VerifyError e) {
     // unavailable
   }
   super.onActivityResult(requestCode, resultCode, data);
 }
 @Override
 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
   if (requestCode == REQUEST_CODE_SYNC
       && resultCode == SyncProviderPreferences.RESULT_CODE_SYNCHRONIZE) {
     setResult(SyncProviderPreferences.RESULT_CODE_SYNCHRONIZE);
     finish();
     return;
   } else if (requestCode == REQUEST_CODE_PERFORMANCE
       && resultCode == LabsPreferences.PERFORMANCE_SETTING_CHANGED) {
     setResult(RESULT_CODE_PERFORMANCE_PREF_CHANGED);
     return;
   }
   try {
     VoiceOutputService.getVoiceOutputInstance()
         .handleActivityResult(requestCode, resultCode, data);
   } catch (VerifyError e) {
     // unavailable
   }
   super.onActivityResult(requestCode, resultCode, data);
 }
  @Override
  /** Alarm intent */
  public void onReceive(Context context, Intent intent) {
    ContextManager.setContext(context);

    long id = intent.getLongExtra(ID_KEY, 0);
    int type = intent.getIntExtra(TYPE_KEY, (byte) 0);

    Resources r = context.getResources();
    String reminder;

    if (type == ReminderService.TYPE_ALARM)
      reminder = getRandomReminder(r.getStringArray(R.array.reminders_alarm));
    else if (Preferences.getBoolean(R.string.p_rmd_nagging, true)) {
      if (type == ReminderService.TYPE_DUE || type == ReminderService.TYPE_OVERDUE)
        reminder = getRandomReminder(r.getStringArray(R.array.reminders_due));
      else if (type == ReminderService.TYPE_SNOOZE)
        reminder = getRandomReminder(r.getStringArray(R.array.reminders_snooze));
      else reminder = getRandomReminder(r.getStringArray(R.array.reminders));
    } else reminder = ""; // $NON-NLS-1$

    synchronized (Notifications.class) {
      if (notificationManager == null)
        notificationManager = new AndroidNotificationManager(context);
    }

    if (!showTaskNotification(id, type, reminder)) {
      notificationManager.cancel((int) id);
    }

    try {
      VoiceOutputService.getVoiceOutputInstance().onDestroy();
    } catch (VerifyError e) {
      // unavailable
    }
  }
  /**
   * Shows an Astrid notification. Pulls in ring tone and quiet hour settings from preferences. You
   * can make it say anything you like.
   *
   * @param ringTimes number of times to ring (-1 = nonstop)
   */
  public static void showNotification(
      int notificationId, Intent intent, int type, String title, String text, int ringTimes) {
    Context context = ContextManager.getContext();
    if (notificationManager == null) notificationManager = new AndroidNotificationManager(context);

    // quiet hours? unless alarm clock
    boolean quietHours = false;
    int quietHoursStart = Preferences.getIntegerFromString(R.string.p_rmd_quietStart, -1);
    int quietHoursEnd = Preferences.getIntegerFromString(R.string.p_rmd_quietEnd, -1);
    if (quietHoursStart != -1 && quietHoursEnd != -1 && ringTimes >= 0) {
      int hour = new Date().getHours();
      if (quietHoursStart <= quietHoursEnd) {
        if (hour >= quietHoursStart && hour < quietHoursEnd) quietHours = true;
      } else { // wrap across 24/hour boundary
        if (hour >= quietHoursStart || hour < quietHoursEnd) quietHours = true;
      }
    }

    PendingIntent pendingIntent =
        PendingIntent.getActivity(
            context, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);

    // set up properties (name and icon) for the notification
    int icon;
    switch (Preferences.getIntegerFromString(R.string.p_rmd_icon, ICON_SET_ASTRID)) {
      case ICON_SET_PINK:
        icon = R.drawable.notif_pink_alarm;
        break;
      case ICON_SET_BORING:
        icon = R.drawable.notif_boring_alarm;
        break;
      default:
        icon = R.drawable.notif_astrid;
    }

    // create notification object
    Notification notification = new Notification(icon, text, System.currentTimeMillis());
    notification.setLatestEventInfo(context, title, text, pendingIntent);
    notification.flags |= Notification.FLAG_AUTO_CANCEL;
    if (Preferences.getBoolean(R.string.p_rmd_persistent, true)) {
      notification.flags |= Notification.FLAG_NO_CLEAR | Notification.FLAG_SHOW_LIGHTS;
      notification.ledOffMS = 5000;
      notification.ledOnMS = 700;
      notification.ledARGB = Color.YELLOW;
    } else notification.defaults = Notification.DEFAULT_LIGHTS;

    AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);

    // detect call state
    TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
    int callState = tm.getCallState();

    boolean voiceReminder = Preferences.getBoolean(R.string.p_voiceRemindersEnabled, false);

    // if multi-ring is activated, set up the flags for insistent
    // notification, and increase the volume to full volume, so the user
    // will actually pay attention to the alarm
    if (ringTimes != 1 && (type != ReminderService.TYPE_RANDOM)) {
      notification.audioStreamType = AudioManager.STREAM_ALARM;
      audioManager.setStreamVolume(
          AudioManager.STREAM_ALARM, audioManager.getStreamMaxVolume(AudioManager.STREAM_ALARM), 0);

      // insistent rings until notification is disabled
      if (ringTimes < 0) {
        notification.flags |= Notification.FLAG_INSISTENT;
        voiceReminder = false;
      }

    } else {
      notification.audioStreamType = AudioManager.STREAM_NOTIFICATION;
    }

    // quiet hours = no sound
    if (quietHours || callState != TelephonyManager.CALL_STATE_IDLE) {
      notification.sound = null;
      voiceReminder = false;
    } else {
      String notificationPreference = Preferences.getStringValue(R.string.p_rmd_ringtone);
      if (audioManager.getStreamVolume(AudioManager.STREAM_RING) == 0) {
        notification.sound = null;
        voiceReminder = false;
      } else if (notificationPreference != null) {
        if (notificationPreference.length() > 0) {
          Uri notificationSound = Uri.parse(notificationPreference);
          notification.sound = notificationSound;
        } else {
          notification.sound = null;
        }
      } else {
        notification.defaults |= Notification.DEFAULT_SOUND;
      }
    }

    // quiet hours && ! due date or snooze = no vibrate
    if (quietHours && !(type == ReminderService.TYPE_DUE || type == ReminderService.TYPE_SNOOZE)) {
      notification.vibrate = null;
    } else if (callState != TelephonyManager.CALL_STATE_IDLE) {
      notification.vibrate = null;
    } else {
      if (Preferences.getBoolean(R.string.p_rmd_vibrate, true)
          && audioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_NOTIFICATION)) {
        notification.vibrate = new long[] {0, 1000, 500, 1000, 500, 1000};
      } else {
        notification.vibrate = null;
      }
    }

    if (Constants.DEBUG)
      Log.w("Astrid", "Logging notification: " + text); // $NON-NLS-1$ //$NON-NLS-2$

    for (int i = 0; i < Math.max(ringTimes, 1); i++) {
      notificationManager.notify(notificationId, notification);
      AndroidUtilities.sleepDeep(500);
    }

    if (voiceReminder) {
      AndroidUtilities.sleepDeep(2000);
      for (int i = 0; i < 50; i++) {
        AndroidUtilities.sleepDeep(500);
        if (audioManager.getMode() != AudioManager.MODE_RINGTONE) break;
      }
      try {
        VoiceOutputService.getVoiceOutputInstance().queueSpeak(text);
      } catch (VerifyError e) {
        // unavailable
      }
    }
  }