/* This file is part of BeepMe. BeepMe is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. BeepMe is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with BeepMe. If not, see <http://www.gnu.org/licenses/>. Copyright 2012-2014 Michael Glanznig http://beepme.yourexp.at */ package com.glanznig.beepme.view; import java.lang.ref.WeakReference; import java.util.Calendar; import java.util.Date; import com.fima.glowpadview.GlowPadView; import com.fima.glowpadview.GlowPadView.OnTriggerListener; import com.glanznig.beepme.BeeperApp; import com.glanznig.beepme.R; import com.glanznig.beepme.data.Sample; import com.glanznig.beepme.db.SampleTable; import com.glanznig.beepme.db.ScheduledBeepTable; import com.glanznig.beepme.db.UptimeTable; import com.glanznig.beepme.helper.BeepAlert; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.res.Configuration; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.widget.TextView; public class BeepActivity extends Activity { private static class TimeoutHandler extends Handler { WeakReference<BeepActivity> beepActivity; TimeoutHandler(BeepActivity activity) { beepActivity = new WeakReference<BeepActivity>(activity); } @Override public void handleMessage(Message message) { if (beepActivity.get() != null) { beepActivity.get().decline(); } } } // Controller for GlowPadView (thanks to AOSP) private class GlowPadController extends Handler implements OnTriggerListener { private static final int PING_MESSAGE_WHAT = 101; private static final long PING_AUTO_REPEAT_DELAY_MSEC = 1200; public void startPinger() { sendEmptyMessage(PING_MESSAGE_WHAT); } public void stopPinger() { removeMessages(PING_MESSAGE_WHAT); } @Override public void handleMessage(Message msg) { ping(); sendEmptyMessageDelayed(PING_MESSAGE_WHAT, PING_AUTO_REPEAT_DELAY_MSEC); } @Override public void onGrabbed(View v, int handle) { stopPinger(); } @Override public void onReleased(View v, int handle) { startPinger(); } @Override public void onTrigger(View v, int target) { final int resId = acceptDeclineHandle.getResourceIdForTarget(target); switch (resId) { case R.drawable.ic_item_accept: accept(); break; case R.drawable.ic_item_decline: decline(); break; case R.drawable.ic_item_beeper_off: declinePause(); break; } } @Override public void onGrabbedStateChange(View v, int handle) { } @Override public void onFinishFinalAnimation() { } } private static final String TAG = "BeepActivity"; public static final String CANCEL_INTENT = "com.glanznig.beepme.DECLINE_BEEP"; public static final int BEEP_TIMEOUT = 15; private GlowPadView acceptDeclineHandle; private GlowPadController glowPadCtrl = new GlowPadController(); private long beepTimestamp; private BeepAlert alert = null; private TimeoutHandler handler = null; private BroadcastReceiver cancelReceiver = null; private BroadcastReceiver screenStateReceiver = null; private boolean inDecline = false; private boolean hasAccepted = false; public void onCreate(Bundle savedState) { super.onCreate(savedState); final Window win = getWindow(); win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON); final BeeperApp app = (BeeperApp)getApplication(); if (savedState != null) { if (!savedState.containsKey("beepTimestamp")) { // set beep timestamp to NOW beepTimestamp = Calendar.getInstance().getTimeInMillis(); new ScheduledBeepTable(this.getApplicationContext()).receivedScheduledBeep( app.getPreferences().getScheduledBeepId(), beepTimestamp); } else { beepTimestamp = savedState.getLong("beepTimestamp"); } } else { // set beep timestamp to NOW beepTimestamp = Calendar.getInstance().getTimeInMillis(); new ScheduledBeepTable(this.getApplicationContext()).receivedScheduledBeep( app.getPreferences().getScheduledBeepId(), beepTimestamp); } handler = new TimeoutHandler(BeepActivity.this); // decline and pause beeper if active call if (app.getPreferences().getPauseBeeperDuringCall() && app.getPreferences().isCall()) { app.setBeeperActive(BeeperApp.BEEPER_INACTIVE_AFTER_CALL); decline(); return; } updateLayout(); // set up broadcast receiver to detect screen events screenStateReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { decline(); } } }; registerReceiver(screenStateReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF)); // set up broadcast receiver to decline beep at incoming call cancelReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(CANCEL_INTENT)) { if (app.getPreferences().getPauseBeeperDuringCall()) { app.setBeeperActive(BeeperApp.BEEPER_INACTIVE_AFTER_CALL); decline(); } } } }; registerReceiver(cancelReceiver, new IntentFilter(CANCEL_INTENT)); alert = new BeepAlert(BeepActivity.this); SampleTable st = new SampleTable(this.getApplicationContext()); int numAccepted = st.getNumAcceptedToday(); int numDeclined = st.getSampleCountToday() - numAccepted; long uptimeDur = new UptimeTable(this.getApplicationContext(), app.getTimerProfile()).getUptimeDurToday(); TextView acceptedToday = (TextView)findViewById(R.id.beep_accepted_today); TextView declinedToday = (TextView)findViewById(R.id.beep_declined_today); TextView beeperActive = (TextView)findViewById(R.id.beep_elapsed_today); String timeActive = String.format("%02d:%02d:%02d", uptimeDur/3600, (uptimeDur%3600)/60, (uptimeDur%60)); acceptedToday.setText(String.valueOf(numAccepted)); declinedToday.setText(String.valueOf(numDeclined)); beeperActive.setText(String.valueOf(timeActive)); } @Override protected void onPause() { super.onPause(); glowPadCtrl.stopPinger(); alert.stop(); handler.removeMessages(BEEP_TIMEOUT); } @Override protected void onResume() { super.onResume(); long timeSinceBeep = Math.abs(Calendar.getInstance().getTimeInMillis() - beepTimestamp); if (timeSinceBeep < 30000) { // max 30 sec timeout for beep handler.sendEmptyMessageDelayed(BEEP_TIMEOUT, 30000 - timeSinceBeep); } else { // timeout already elapsed decline(); } glowPadCtrl.startPinger(); alert.start(); } @Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(screenStateReceiver); unregisterReceiver(cancelReceiver); } private void ping() { acceptDeclineHandle.ping(); } private void updateLayout() { final LayoutInflater inflater = LayoutInflater.from(this); final View view = inflater.inflate(R.layout.beep, null); view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE); setContentView(view); acceptDeclineHandle = (GlowPadView)findViewById(R.id.beep_glowpad); acceptDeclineHandle.setOnTriggerListener(glowPadCtrl); glowPadCtrl.startPinger(); //acceptDeclineHandle.setShowTargetsOnIdle(true); } public void accept() { hasAccepted = true; if (alert != null) { alert.stop(); } BeeperApp app = (BeeperApp)getApplication(); app.acceptTimer(); Intent accept = new Intent(BeepActivity.this, NewSampleActivity.class); accept.putExtra(getApplication().getClass().getPackage().getName() + ".Timestamp", beepTimestamp); startActivity(accept); } public void declinePause() { BeeperApp app = (BeeperApp)getApplication(); app.setBeeperActive(BeeperApp.BEEPER_INACTIVE); decline(); } public void decline() { if (!inDecline) { // should only be called once inDecline = true; BeeperApp app = (BeeperApp) getApplication(); Sample sample = new Sample(); sample.setTimestamp(new Date(beepTimestamp)); sample.setAccepted(false); sample.setUptimeId(app.getPreferences().getUptimeId()); new SampleTable(this.getApplicationContext()).addSample(sample); app.declineTimer(); app.setTimer(); if (!BeepActivity.this.isFinishing()) { finish(); } } } @Override protected void onUserLeaveHint() { // user leaves the activity if (!hasAccepted) { decline(); } } @Override public void onBackPressed() { // Don't allow back to decline. } @Override public boolean dispatchKeyEvent(KeyEvent event) { switch (event.getKeyCode()) { case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_DOWN: case KeyEvent.KEYCODE_VOLUME_MUTE: case KeyEvent.KEYCODE_CAMERA: case KeyEvent.KEYCODE_FOCUS: decline(); return true; } return super.dispatchKeyEvent(event); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); updateLayout(); } @Override public void onSaveInstanceState(Bundle savedState) { savedState.putLong("beepTimestamp", beepTimestamp); } }