Java tutorial
/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.wizardsofm.deskclock.alarms; import android.accessibilityservice.AccessibilityServiceInfo; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.animation.TimeInterpolator; import android.animation.ValueAnimator; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.content.pm.ActivityInfo; import android.graphics.Color; import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.media.Ringtone; import android.os.Bundle; import android.os.CountDownTimer; import android.os.Handler; import android.os.IBinder; import android.speech.RecognitionListener; import android.speech.RecognizerIntent; import android.speech.SpeechRecognizer; import android.support.annotation.NonNull; import android.support.v4.graphics.ColorUtils; import android.support.v4.view.animation.PathInterpolatorCompat; import android.support.v7.app.AppCompatActivity; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.view.accessibility.AccessibilityManager; import android.widget.ImageView; import android.widget.TextClock; import android.widget.TextView; import android.widget.Toast; import com.wizardsofm.deskclock.AnimatorUtils; import com.wizardsofm.deskclock.LogUtils; import com.wizardsofm.deskclock.R; import com.wizardsofm.deskclock.Utils; import com.wizardsofm.deskclock.data.DataModel; import com.wizardsofm.deskclock.events.Events; import com.wizardsofm.deskclock.provider.AlarmInstance; import com.wizardsofm.deskclock.settings.SettingsActivity; import com.wizardsofm.deskclock.uidata.UiDataModel; import com.wizardsofm.deskclock.widget.CircleView; import com.wizardsofm.voice.SpeechRecognizerManager; import java.util.ArrayList; import java.util.List; import java.util.Locale; import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_GENERIC; import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD; import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; import static android.view.WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON; import static android.widget.Toast.makeText; public class AlarmActivity extends AppCompatActivity implements View.OnClickListener, View.OnTouchListener, RecognitionListener { private static final LogUtils.Logger LOGGER = new LogUtils.Logger("AlarmActivity"); private static final TimeInterpolator PULSE_INTERPOLATOR = PathInterpolatorCompat.create(0.4f, 0.0f, 0.2f, 1.0f); private static final TimeInterpolator REVEAL_INTERPOLATOR = PathInterpolatorCompat.create(0.0f, 0.0f, 0.2f, 1.0f); private static final int PULSE_DURATION_MILLIS = 1000; private static final int ALARM_BOUNCE_DURATION_MILLIS = 500; private static final int ALERT_REVEAL_DURATION_MILLIS = 500; private static final int ALERT_FADE_DURATION_MILLIS = 500; private static final int ALERT_DISMISS_DELAY_MILLIS = 2000; private static final float BUTTON_SCALE_DEFAULT = 0.7f; private static final int BUTTON_DRAWABLE_ALPHA_DEFAULT = 165; private SpeechRecognizerManager mSpeechRecognizerManager; //make an enum later for status : snooze,stop boolean alarmSnoozed = false; private AlarmActivity thisContext; private SpeechRecognizer speech = null; private Intent i; private Intent intent; Ringtone r; CountDownTimer countDownTimer; boolean resumeCounting = false; //make an enum later for status : snooze,stop boolean alarmStopped = false; private final Handler mHandler = new Handler(); private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); LOGGER.v("Received broadcast: %s", action); if (!mAlarmHandled) { switch (action) { case AlarmService.ALARM_SNOOZE_ACTION: snooze(); break; case AlarmService.ALARM_DISMISS_ACTION: dismiss(); break; case AlarmService.ALARM_DONE_ACTION: finish(); break; default: LOGGER.i("Unknown broadcast: %s", action); break; } } else { LOGGER.v("Ignored broadcast: %s", action); } } }; private final ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { LOGGER.i("Finished binding to AlarmService"); } @Override public void onServiceDisconnected(ComponentName name) { LOGGER.i("Disconnected from AlarmService"); } }; private AlarmInstance mAlarmInstance; private boolean mAlarmHandled; private String mVolumeBehavior; private int mCurrentHourColor; private boolean mReceiverRegistered; /** Whether the AlarmService is currently bound */ private boolean mServiceBound; private AccessibilityManager mAccessibilityManager; private ViewGroup mAlertView; private TextView mAlertTitleView; private TextView mAlertInfoView; private ViewGroup mContentView; private ImageView mAlarmButton; private ImageView mSnoozeButton; private ImageView mDismissButton; private TextView mHintView; private ValueAnimator mAlarmAnimator; private ValueAnimator mSnoozeAnimator; private ValueAnimator mDismissAnimator; private ValueAnimator mPulseAnimator; private int mInitialPointerIndex = MotionEvent.INVALID_POINTER_ID; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); final long instanceId = AlarmInstance.getId(getIntent().getData()); mAlarmInstance = AlarmInstance.getInstance(getContentResolver(), instanceId); if (mAlarmInstance == null) { // The alarm was deleted before the activity got created, so just finish() LOGGER.e("Error displaying alarm for intent: %s", getIntent()); finish(); return; } else if (mAlarmInstance.mAlarmState != AlarmInstance.FIRED_STATE) { LOGGER.i("Skip displaying alarm for instance: %s", mAlarmInstance); finish(); return; } LOGGER.i("Displaying alarm for instance: %s", mAlarmInstance); // Get the volume/camera button behavior setting mVolumeBehavior = Utils.getDefaultSharedPreferences(this).getString(SettingsActivity.KEY_VOLUME_BUTTONS, SettingsActivity.DEFAULT_VOLUME_BEHAVIOR); getWindow().addFlags(FLAG_SHOW_WHEN_LOCKED | FLAG_DISMISS_KEYGUARD | FLAG_KEEP_SCREEN_ON | FLAG_TURN_SCREEN_ON | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON); // Hide navigation bar to minimize accidental tap on Home key hideNavigationBar(); // Close dialogs and window shade, so this is fully visible sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); // Honor rotation on tablets; fix the orientation on phones. if (!getResources().getBoolean(R.bool.config_rotateAlarmAlert)) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR); } mAccessibilityManager = (AccessibilityManager) getSystemService(ACCESSIBILITY_SERVICE); setContentView(R.layout.alarm_activity); mAlertView = (ViewGroup) findViewById(R.id.alert); mAlertTitleView = (TextView) mAlertView.findViewById(R.id.alert_title); mAlertInfoView = (TextView) mAlertView.findViewById(R.id.alert_info); mContentView = (ViewGroup) findViewById(R.id.content); mAlarmButton = (ImageView) mContentView.findViewById(R.id.alarm); mSnoozeButton = (ImageView) mContentView.findViewById(R.id.snooze); mDismissButton = (ImageView) mContentView.findViewById(R.id.dismiss); mHintView = (TextView) mContentView.findViewById(R.id.hint); final TextView titleView = (TextView) mContentView.findViewById(R.id.title); final TextClock digitalClock = (TextClock) mContentView.findViewById(R.id.digital_clock); final CircleView pulseView = (CircleView) mContentView.findViewById(R.id.pulse); // PowerManager pm = (PowerManager) getApplicationContext().getSystemService(Context.POWER_SERVICE); // PowerManager.WakeLock wakeLock = pm.newWakeLock((PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP), "TAG"); // wakeLock.acquire(); // // // // KeyguardManager keyguardManager = (KeyguardManager) getApplicationContext().getSystemService(Context.KEYGUARD_SERVICE); // KeyguardManager.KeyguardLock keyguardLock = keyguardManager.newKeyguardLock("TAG"); // keyguardLock.disableKeyguard(); titleView.setText(mAlarmInstance.getLabelOrDefault(this)); Utils.setTimeFormat(digitalClock); mCurrentHourColor = UiDataModel.getUiDataModel().getWindowBackgroundColor(); getWindow().setBackgroundDrawable(new ColorDrawable(mCurrentHourColor)); mAlarmButton.setOnTouchListener(this); mSnoozeButton.setOnClickListener(this); mDismissButton.setOnClickListener(this); mAlarmAnimator = AnimatorUtils.getScaleAnimator(mAlarmButton, 1.0f, 0.0f); mSnoozeAnimator = getButtonAnimator(mSnoozeButton, Color.WHITE); mDismissAnimator = getButtonAnimator(mDismissButton, mCurrentHourColor); mPulseAnimator = ObjectAnimator.ofPropertyValuesHolder(pulseView, PropertyValuesHolder.ofFloat(CircleView.RADIUS, 0.0f, pulseView.getRadius()), PropertyValuesHolder.ofObject(CircleView.FILL_COLOR, AnimatorUtils.ARGB_EVALUATOR, ColorUtils.setAlphaComponent(pulseView.getFillColor(), 0))); mPulseAnimator.setDuration(PULSE_DURATION_MILLIS); mPulseAnimator.setInterpolator(PULSE_INTERPOLATOR); mPulseAnimator.setRepeatCount(ValueAnimator.INFINITE); mPulseAnimator.start(); if (DataModel.getDataModel().getSnoozeByVoice()) { startListening(); } // if (DataModel.getDataModel().getSnoozeByVoice()) { // thisContext = this; // Thread t1 = new Thread(new Runnable() { // public void run() { // mSpeechRecognizerManager = SpeechRecognizerManager.getInstance(thisContext); //new SpeechRecognizerManager(thisContext); // } // }); // t1.start(); // // } } @Override protected void onResume() { super.onResume(); // Thread t1 = new Thread(new Runnable() { // public void run() { // listenForCommand(); // } // }); // t1.start(); // // Re-query for AlarmInstance in case the state has changed externally // final long instanceId = AlarmInstance.getId(getIntent().getData()); // mAlarmInstance = AlarmInstance.getInstance(getContentResolver(), instanceId); // // if (mAlarmInstance == null) { // LOGGER.i("No alarm instance for instanceId: %d", instanceId); // finish(); // return; // } // // // Verify that the alarm is still firing before showing the activity // if (mAlarmInstance.mAlarmState != AlarmInstance.FIRED_STATE) { // LOGGER.i("Skip displaying alarm for instance: %s", mAlarmInstance); // finish(); // return; // } // // if (!mReceiverRegistered) { // // Register to get the alarm done/snooze/dismiss intent. // final IntentFilter filter = new IntentFilter(AlarmService.ALARM_DONE_ACTION); // filter.addAction(AlarmService.ALARM_SNOOZE_ACTION); // filter.addAction(AlarmService.ALARM_DISMISS_ACTION); // registerReceiver(mReceiver, filter); // mReceiverRegistered = true; // } // // bindAlarmService(); // // resetAnimations(); } @Override protected void onPause() { super.onPause(); // unbindAlarmService(); // Skip if register didn't happen to avoid IllegalArgumentException // if (mReceiverRegistered) { // unregisterReceiver(mReceiver); // mReceiverRegistered = false; // } } @Override public boolean dispatchKeyEvent(@NonNull KeyEvent keyEvent) { // Do this in dispatch to intercept a few of the system keys. LOGGER.v("dispatchKeyEvent: %s", keyEvent); switch (keyEvent.getKeyCode()) { // Volume keys and camera keys dismiss the alarm. case KeyEvent.KEYCODE_POWER: case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_DOWN: case KeyEvent.KEYCODE_VOLUME_MUTE: case KeyEvent.KEYCODE_HEADSETHOOK: case KeyEvent.KEYCODE_CAMERA: case KeyEvent.KEYCODE_FOCUS: if (!mAlarmHandled && keyEvent.getAction() == KeyEvent.ACTION_UP) { switch (mVolumeBehavior) { case SettingsActivity.VOLUME_BEHAVIOR_SNOOZE: snooze(); break; case SettingsActivity.VOLUME_BEHAVIOR_DISMISS: dismiss(); break; default: break; } } return true; default: return super.dispatchKeyEvent(keyEvent); } } @Override public void onBackPressed() { // Don't allow back to dismiss. } @Override public void onClick(View view) { if (mAlarmHandled) { LOGGER.v("onClick ignored: %s", view); return; } LOGGER.v("onClick: %s", view); // If in accessibility mode, allow snooze/dismiss by double tapping on respective icons. if (isAccessibilityEnabled()) { if (view == mSnoozeButton) { snooze(); } else if (view == mDismissButton) { dismiss(); } return; } if (view == mSnoozeButton) { hintSnooze(); } else if (view == mDismissButton) { hintDismiss(); } } @Override public boolean onTouch(View view, MotionEvent event) { if (mAlarmHandled) { LOGGER.v("onTouch ignored: %s", event); return false; } final int action = event.getActionMasked(); if (action == MotionEvent.ACTION_DOWN) { LOGGER.v("onTouch started: %s", event); // Track the pointer that initiated the touch sequence. mInitialPointerIndex = event.getPointerId(event.getActionIndex()); // Stop the pulse, allowing the last pulse to finish. mPulseAnimator.setRepeatCount(0); } else if (action == MotionEvent.ACTION_CANCEL) { LOGGER.v("onTouch canceled: %s", event); // Clear the pointer index. mInitialPointerIndex = MotionEvent.INVALID_POINTER_ID; // Reset everything. resetAnimations(); } final int actionIndex = event.getActionIndex(); if (mInitialPointerIndex == MotionEvent.INVALID_POINTER_ID || mInitialPointerIndex != event.getPointerId(actionIndex)) { // Ignore any pointers other than the initial one, bail early. return true; } final int[] contentLocation = { 0, 0 }; mContentView.getLocationOnScreen(contentLocation); final float x = event.getRawX() - contentLocation[0]; final float y = event.getRawY() - contentLocation[1]; final int alarmLeft = mAlarmButton.getLeft() + mAlarmButton.getPaddingLeft(); final int alarmRight = mAlarmButton.getRight() - mAlarmButton.getPaddingRight(); final float snoozeFraction, dismissFraction; if (mContentView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) { snoozeFraction = getFraction(alarmRight, mSnoozeButton.getLeft(), x); dismissFraction = getFraction(alarmLeft, mDismissButton.getRight(), x); } else { snoozeFraction = getFraction(alarmLeft, mSnoozeButton.getRight(), x); dismissFraction = getFraction(alarmRight, mDismissButton.getLeft(), x); } setAnimatedFractions(snoozeFraction, dismissFraction); if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP) { LOGGER.v("onTouch ended: %s", event); mInitialPointerIndex = MotionEvent.INVALID_POINTER_ID; if (snoozeFraction == 1.0f) { snooze(); } else if (dismissFraction == 1.0f) { dismiss(); } else { if (snoozeFraction > 0.0f || dismissFraction > 0.0f) { // Animate back to the initial state. AnimatorUtils.reverse(mAlarmAnimator, mSnoozeAnimator, mDismissAnimator); } else if (mAlarmButton.getTop() <= y && y <= mAlarmButton.getBottom()) { // User touched the alarm button, hint the dismiss action. hintDismiss(); } // Restart the pulse. mPulseAnimator.setRepeatCount(ValueAnimator.INFINITE); if (!mPulseAnimator.isStarted()) { mPulseAnimator.start(); } } } return true; } private void hideNavigationBar() { getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); } /** * Returns {@code true} if accessibility is enabled, to enable alternate behavior for click * handling, etc. */ private boolean isAccessibilityEnabled() { if (mAccessibilityManager == null || !mAccessibilityManager.isEnabled()) { // Accessibility is unavailable or disabled. return false; } else if (mAccessibilityManager.isTouchExplorationEnabled()) { // TalkBack's touch exploration mode is enabled. return true; } // Check if "Switch Access" is enabled. final List<AccessibilityServiceInfo> enabledAccessibilityServices = mAccessibilityManager .getEnabledAccessibilityServiceList(FEEDBACK_GENERIC); return !enabledAccessibilityServices.isEmpty(); } private void hintSnooze() { final int alarmLeft = mAlarmButton.getLeft() + mAlarmButton.getPaddingLeft(); final int alarmRight = mAlarmButton.getRight() - mAlarmButton.getPaddingRight(); final float translationX = Math.max(mSnoozeButton.getLeft() - alarmRight, 0) + Math.min(mSnoozeButton.getRight() - alarmLeft, 0); getAlarmBounceAnimator(translationX, translationX < 0.0f ? R.string.description_direction_left : R.string.description_direction_right) .start(); } private void hintDismiss() { final int alarmLeft = mAlarmButton.getLeft() + mAlarmButton.getPaddingLeft(); final int alarmRight = mAlarmButton.getRight() - mAlarmButton.getPaddingRight(); final float translationX = Math.max(mDismissButton.getLeft() - alarmRight, 0) + Math.min(mDismissButton.getRight() - alarmLeft, 0); getAlarmBounceAnimator(translationX, translationX < 0.0f ? R.string.description_direction_left : R.string.description_direction_right) .start(); } /** * Set animators to initial values and restart pulse on alarm button. */ private void resetAnimations() { // Set the animators to their initial values. setAnimatedFractions(0.0f /* snoozeFraction */, 0.0f /* dismissFraction */); // Restart the pulse. mPulseAnimator.setRepeatCount(ValueAnimator.INFINITE); if (!mPulseAnimator.isStarted()) { mPulseAnimator.start(); } } /** * Perform snooze animation and send snooze intent. */ public void snooze() { mAlarmHandled = true; LOGGER.v("Snoozed: %s", mAlarmInstance); final int accentColor = Utils.obtainStyledColor(this, R.attr.colorAccent, Color.RED); setAnimatedFractions(1.0f /* snoozeFraction */, 0.0f /* dismissFraction */); final int snoozeMinutes = AlarmStateManager.getSnoozedMinutes(this); final String infoText = getResources().getQuantityString(R.plurals.alarm_alert_snooze_duration, snoozeMinutes, snoozeMinutes); final String accessibilityText = getResources().getQuantityString(R.plurals.alarm_alert_snooze_set, snoozeMinutes, snoozeMinutes); getAlertAnimator(mSnoozeButton, R.string.alarm_alert_snoozed_text, infoText, accessibilityText, accentColor, accentColor).start(); AlarmStateManager.setSnoozeState(this, mAlarmInstance, false /* showToast */); Events.sendAlarmEvent(R.string.action_snooze, R.string.label_deskclock); // Unbind here, otherwise alarm will keep ringing until activity finishes. unbindAlarmService(); SpeechRecognizerManager.shutDownTheListener(); } /** * Perform dismiss animation and send dismiss intent. */ public void dismiss() { mAlarmHandled = true; LOGGER.v("Dismissed: %s", mAlarmInstance); setAnimatedFractions(0.0f /* snoozeFraction */, 1.0f /* dismissFraction */); getAlertAnimator(mDismissButton, R.string.alarm_alert_off_text, null /* infoText */, getString(R.string.alarm_alert_off_text) /* accessibilityText */, Color.WHITE, mCurrentHourColor) .start(); AlarmStateManager.deleteInstanceAndUpdateParent(this, mAlarmInstance); Events.sendAlarmEvent(R.string.action_dismiss, R.string.label_deskclock); // Unbind here, otherwise alarm will keep ringing until activity finishes. unbindAlarmService(); SpeechRecognizerManager.shutDownTheListener(); } /** * Bind AlarmService if not yet bound. */ private void bindAlarmService() { if (!mServiceBound) { final Intent intent = new Intent(this, AlarmService.class); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); mServiceBound = true; } } /** * Unbind AlarmService if bound. */ private void unbindAlarmService() { if (mServiceBound) { unbindService(mConnection); mServiceBound = false; } } private void setAnimatedFractions(float snoozeFraction, float dismissFraction) { final float alarmFraction = Math.max(snoozeFraction, dismissFraction); AnimatorUtils.setAnimatedFraction(mAlarmAnimator, alarmFraction); AnimatorUtils.setAnimatedFraction(mSnoozeAnimator, snoozeFraction); AnimatorUtils.setAnimatedFraction(mDismissAnimator, dismissFraction); } private float getFraction(float x0, float x1, float x) { return Math.max(Math.min((x - x0) / (x1 - x0), 1.0f), 0.0f); } private ValueAnimator getButtonAnimator(ImageView button, int tintColor) { return ObjectAnimator.ofPropertyValuesHolder(button, PropertyValuesHolder.ofFloat(View.SCALE_X, BUTTON_SCALE_DEFAULT, 1.0f), PropertyValuesHolder.ofFloat(View.SCALE_Y, BUTTON_SCALE_DEFAULT, 1.0f), PropertyValuesHolder.ofInt(AnimatorUtils.BACKGROUND_ALPHA, 0, 255), PropertyValuesHolder.ofInt(AnimatorUtils.DRAWABLE_ALPHA, BUTTON_DRAWABLE_ALPHA_DEFAULT, 255), PropertyValuesHolder.ofObject(AnimatorUtils.DRAWABLE_TINT, AnimatorUtils.ARGB_EVALUATOR, Color.WHITE, tintColor)); } private ValueAnimator getAlarmBounceAnimator(float translationX, final int hintResId) { final ValueAnimator bounceAnimator = ObjectAnimator.ofFloat(mAlarmButton, View.TRANSLATION_X, mAlarmButton.getTranslationX(), translationX, 0.0f); bounceAnimator.setInterpolator(AnimatorUtils.DECELERATE_ACCELERATE_INTERPOLATOR); bounceAnimator.setDuration(ALARM_BOUNCE_DURATION_MILLIS); bounceAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animator) { mHintView.setText(hintResId); if (mHintView.getVisibility() != View.VISIBLE) { mHintView.setVisibility(View.VISIBLE); ObjectAnimator.ofFloat(mHintView, View.ALPHA, 0.0f, 1.0f).start(); } } }); return bounceAnimator; } private Animator getAlertAnimator(final View source, final int titleResId, final String infoText, final String accessibilityText, final int revealColor, final int backgroundColor) { final ViewGroup containerView = (ViewGroup) findViewById(android.R.id.content); final Rect sourceBounds = new Rect(0, 0, source.getHeight(), source.getWidth()); containerView.offsetDescendantRectToMyCoords(source, sourceBounds); final int centerX = sourceBounds.centerX(); final int centerY = sourceBounds.centerY(); final int xMax = Math.max(centerX, containerView.getWidth() - centerX); final int yMax = Math.max(centerY, containerView.getHeight() - centerY); final float startRadius = Math.max(sourceBounds.width(), sourceBounds.height()) / 2.0f; final float endRadius = (float) Math.sqrt(xMax * xMax + yMax * yMax); final CircleView revealView = new CircleView(this).setCenterX(centerX).setCenterY(centerY) .setFillColor(revealColor); containerView.addView(revealView); // TODO: Fade out source icon over the reveal (like LOLLIPOP version). final Animator revealAnimator = ObjectAnimator.ofFloat(revealView, CircleView.RADIUS, startRadius, endRadius); revealAnimator.setDuration(ALERT_REVEAL_DURATION_MILLIS); revealAnimator.setInterpolator(REVEAL_INTERPOLATOR); revealAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animator) { mAlertView.setVisibility(View.VISIBLE); mAlertTitleView.setText(titleResId); if (infoText != null) { mAlertInfoView.setText(infoText); mAlertInfoView.setVisibility(View.VISIBLE); } mContentView.setVisibility(View.GONE); getWindow().setBackgroundDrawable(new ColorDrawable(backgroundColor)); } }); final ValueAnimator fadeAnimator = ObjectAnimator.ofFloat(revealView, View.ALPHA, 0.0f); fadeAnimator.setDuration(ALERT_FADE_DURATION_MILLIS); fadeAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { containerView.removeView(revealView); } }); final AnimatorSet alertAnimator = new AnimatorSet(); alertAnimator.play(revealAnimator).before(fadeAnimator); alertAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animator) { mAlertView.announceForAccessibility(accessibilityText); mHandler.postDelayed(new Runnable() { @Override public void run() { finish(); } }, ALERT_DISMISS_DELAY_MILLIS); } }); return alertAnimator; } void listenForCommand() { // if (speech == null) { // speech = SpeechRecognizer.createSpeechRecognizer(this); // speech.setRecognitionListener(MainActivity.this); // } // speech = SpeechRecognizer.createSpeechRecognizer(this); // speech.setRecognitionListener(this); i = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); i.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); i.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault()); i.putExtra(RecognizerIntent.EXTRA_PROMPT, "Say something"); // i.putExtra("android.speech.extra.DICTATION_MODE", true); // i.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true); i.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS, 5000); try { startActivityForResult(i, 100); new CountDownTimer(5000, 1000) { public void onTick(long millisUntilFinished) { //do nothing, just let it tick } public void onFinish() { if (!alarmStopped) { listenForCommand(); } } }.start(); // speech.startListening(i); } catch (Exception e) { } } public void onActivityResult(int requestCode, int resultCode, Intent i) { super.onActivityResult(requestCode, resultCode, i); switch (requestCode) { case 100: if (resultCode == RESULT_OK && i != null) { ArrayList<String> result = i.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); if (result.get(0).toUpperCase().contains("SHUT UP".toUpperCase())) { r.stop(); alarmStopped = true; } else { } } break; default: break; } } @Override public void onBeginningOfSpeech() { } @Override public void onBufferReceived(byte[] arg0) { } @Override public void onEndOfSpeech() { } @Override public void onError(int e) { } @Override public void onEvent(int arg0, Bundle arg1) { } @Override public void onPartialResults(Bundle arg0) { } @Override public void onReadyForSpeech(Bundle arg0) { } @Override public void onResults(Bundle data) { resumeCounting = false; ArrayList<String> matches = data.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION); makeText(this, getResources().getString(R.string.you_said) + matches.get(0), Toast.LENGTH_SHORT).show(); if (matches.get(0).toUpperCase().contains("SHUTUP".toUpperCase()) || (matches.get(0).toUpperCase().contains("SHUT UP".toUpperCase()))) { snooze(); speech.cancel(); } else if (matches.get(0).toUpperCase().contains("STOP".toUpperCase())) { dismiss(); speech.cancel(); } else { speech.cancel(); speech.startListening(intent); resumeCounting = true; } } @Override public void onRmsChanged(float arg0) { } public void startListening() { makeText(this, getResources().getString(R.string.prompt_voice_commands), Toast.LENGTH_SHORT).show(); speech = SpeechRecognizer.createSpeechRecognizer(this); speech.setRecognitionListener(this); intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_PREFERENCE, "en"); intent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, this.getPackageName()); // intent.putExtra("android.speech.extra.DICTATION_MODE", true); speech.startListening(intent); resumeCounting = true; keepListening(); } public void keepListening() { countDownTimer = new CountDownTimer(8000, 1000) { public void onTick(long millisUntilFinished) { //do nothing, just let it tick } public void onFinish() { if (resumeCounting) { speech.cancel(); speech.startListening(intent); keepListening(); } } }; countDownTimer.start(); } }