package com.androsz.electricsleepbeta.app; import java.util.Calendar; import java.util.concurrent.atomic.AtomicBoolean; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.os.AsyncTask; import android.os.BatteryManager; import android.os.Bundle; import android.os.IBinder; import android.provider.Settings; import android.text.format.DateFormat; import android.view.View; import android.widget.TextView; import android.widget.Toast; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuItem; import com.androsz.electricsleepbeta.R; import com.androsz.electricsleepbeta.alarmclock.Alarm; import com.androsz.electricsleepbeta.alarmclock.AlarmClock; import com.androsz.electricsleepbeta.alarmclock.Alarms; import com.androsz.electricsleepbeta.widget.SleepChart; public class SleepActivity extends HostActivity { private static final String TAG = SleepActivity.class.getSimpleName(); private class DimScreenTask extends AsyncTask<Void, Void, Void> { private boolean mScreenDimmed = false; public boolean isScreenDimmed() { return mScreenDimmed; } private int timer = 0; @Override protected Void doInBackground(final Void... params) { // just wait without blocking the main thread! while (!isCancelled() && timer < DIM_SCREEN_AFTER_MS) { try { timer += 1000; Thread.sleep(1000); } catch (final InterruptedException e) { e.printStackTrace(); } } return null; } @Override protected void onCancelled() { mScreenDimmed = false; Log.d(TAG, "onCancelled"); super.onCancelled(); } @Override protected void onPostExecute(final Void results) { Log.d(TAG, "onPostExecute"); if (!isCancelled()) { Log.d(TAG, "!isCancelled"); mScreenDimmed = true; // after we have waited, dim the screen on the main thread! startActivity(new Intent(SleepActivity.this, DimSleepActivity.class)); } } @Override protected void onPreExecute() { mScreenDimmed = false; // notify the user that we've received that they need a dimmed // screen setToast(R.string.screen_will_dim); } } private void setToast(int stringId) { Toast.makeText(this, stringId, Toast.LENGTH_SHORT).show(); } private static final int DIM_SCREEN_AFTER_MS = 15000; private static final String SLEEP_CHART = "sleepChart"; public static final String SYNC_CHART = "com.androsz.electricsleepbeta.SYNC_CHART"; public static final String UPDATE_CHART = "com.androsz.electricsleepbeta.UPDATE_CHART"; private final BroadcastReceiver batteryChangedReceiver = new BroadcastReceiver() { @Override public void onReceive(final Context context, final Intent intent) { pluggedIn = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) > 0; airplaneModeNagChanged(); } }; private SleepMonitoringService mMonitoringService = null; DimScreenTask dimScreenTask; private SleepChart sleepChart; private final BroadcastReceiver sleepStoppedReceiver = new BroadcastReceiver() { @Override public void onReceive(final Context context, final Intent intent) { finish(); } }; /** Boolean that indicates whether or not the service is bound. */ private AtomicBoolean mServiceBound; private TextView buttonSleepDim; private TextView buttonSleepPluggedIn; private TextView textAlarmStatus; private TextView textAlarmStatusSub; private final BroadcastReceiver updateChartReceiver = new BroadcastReceiver() { @Override public void onReceive(final Context context, final Intent intent) { sleepChart.sync(intent.getDoubleExtra( SleepMonitoringService.EXTRA_X, 0), intent.getDoubleExtra( SleepMonitoringService.EXTRA_Y, 0)); } }; @Override protected int getContentAreaLayoutId() { return R.layout.activity_sleep; } boolean pluggedIn = false; @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); mServiceBound = new AtomicBoolean(); setTitle(R.string.monitoring_sleep); airplaneModeOn = Settings.System.getInt(getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0) != 0; registerReceiver(sleepStoppedReceiver, new IntentFilter( SleepMonitoringService.SLEEP_STOPPED)); sleepChart = (SleepChart) findViewById(R.id.sleep_movement_chart); sleepChart.setVisibility(View.VISIBLE); // Start the sleep monitoring service startService(new Intent(this, SleepMonitoringService.class)); } @Override public boolean onCreateOptionsMenu(Menu menu) { getSupportMenuInflater().inflate(R.menu.menu_monitoring_sleep, menu); return super.onCreateOptionsMenu(menu); } @Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(sleepStoppedReceiver); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_item_alarms: openAlarms(); break; } return super.onOptionsItemSelected(item); } private void openAlarms() { startActivity(new Intent(this, AlarmClock.class)); } public void onClick(View v) { switch (v.getId()) { case R.id.button_tracking_stop: sendBroadcast(new Intent(SleepMonitoringService.STOP_AND_SAVE_SLEEP)); finish(); break; case R.id.text_alarm_status: case R.id.text_alarm_status_sub: case R.id.layout_alarm_status: openAlarms(); break; } } @Override protected void onPause() { unregisterReceiver(airplaneModeChangedReceiver); unregisterReceiver(updateChartReceiver); unregisterReceiver(batteryChangedReceiver); cancelDimScreenTask(); if (mServiceBound.compareAndSet(true, false)) { unbindService(serviceConnection); } isUserLeaving = false; super.onPause(); } boolean isUserLeaving = false; @Override protected void onUserLeaveHint() { Log.d(TAG, "onUserLeaveHint()"); isUserLeaving = true; super.onUserLeaveHint(); } private void cancelDimScreenTask() { Log.d(TAG, "cancelDimScreenTask"); // cancel the dim screen task if it hasn't completed if (dimScreenTask != null) { Log.d(TAG, "dimScreenTask != null"); dimScreenTask.cancel(true); // only show this toast is the user is leaving and the screen has // not been dimmed by the dimScreenTask. if (!dimScreenTask.isScreenDimmed() && (isUserLeaving || isFinishing())) { Log.d(TAG, "!screenDimmed && isUserLeaving"); setToast(R.string.warning_dim_sleep_mode_can_only_occur_on_the_sleep_screen_); } } } boolean airplaneModeOn = false; BroadcastReceiver airplaneModeChangedReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { airplaneModeOn = intent.getBooleanExtra("state", false); airplaneModeNagChanged(); } }; private void airplaneModeNagChanged() { final int visibility = (pluggedIn || airplaneModeOn ? View.GONE : View.VISIBLE); buttonSleepPluggedIn.setVisibility(visibility); } @Override protected void onResume() { textAlarmStatus = (TextView) findViewById(R.id.text_alarm_status); textAlarmStatusSub = (TextView) findViewById(R.id.text_alarm_status_sub); buttonSleepDim = (TextView) findViewById(R.id.text_sleep_dim); buttonSleepPluggedIn = (TextView) findViewById(R.id.text_sleep_plugged_in); registerReceiver(airplaneModeChangedReceiver, new IntentFilter( Intent.ACTION_AIRPLANE_MODE_CHANGED)); registerReceiver(batteryChangedReceiver, new IntentFilter( Intent.ACTION_BATTERY_CHANGED)); registerReceiver(updateChartReceiver, new IntentFilter(UPDATE_CHART)); if (mServiceBound.compareAndSet(false, true)) { bindService(new Intent(this, SleepMonitoringService.class), serviceConnection, Context.BIND_AUTO_CREATE); } super.onResume(); } private ServiceConnection serviceConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder iBinder) { SleepMonitoringService.ServiceBinder binder = (SleepMonitoringService.ServiceBinder) iBinder; mMonitoringService = binder.getService(); sleepChart.setCalibrationLevelAndRedraw(mMonitoringService .getAlarmTriggerSensitivity()); sleepChart.sync(mMonitoringService.getData()); final boolean useAlarm = mMonitoringService.getUseAlarm(); final boolean forceScreenOn = mMonitoringService.getForceScreenOn(); // dims the screen while in this activity and // forceScreenOn is // enabled if (forceScreenOn) { buttonSleepDim.setVisibility(View.VISIBLE); cancelDimScreenTask(); dimScreenTask = new DimScreenTask(); dimScreenTask.execute(); } else { buttonSleepDim.setVisibility(View.GONE); } new AsyncTask<Void, Void, String[]>() { @Override protected String[] doInBackground(Void... params) { String[] result = null; final Alarm alarm = Alarms .calculateNextAlert(SleepActivity.this); if (alarm != null) { final Calendar alarmTime = Calendar.getInstance(); alarmTime.setTimeInMillis(alarm.time); java.text.DateFormat df = DateFormat .getDateFormat(SleepActivity.this); df = DateFormat.getTimeFormat(SleepActivity.this); final String dateTime = df.format(alarmTime.getTime()); final int alarmWindow = mMonitoringService .getAlarmWindow(); alarmTime.add(Calendar.MINUTE, -1 * alarmWindow); final String dateTimePre = df.format(alarmTime .getTime()); result = new String[] { dateTimePre, dateTime }; } return result; } @Override protected void onPostExecute(String[] result) { if (textAlarmStatus != null) { if (result != null) { if (useAlarm) { textAlarmStatus.setText(getString( R.string.alarm_status_range, result[0], result[1])); textAlarmStatus .setCompoundDrawablesWithIntrinsicBounds( getResources() .getDrawable( R.drawable.ic_alarm_pressed), null, null, null); textAlarmStatusSub .setText(R.string.attempt_to_use_smartwake_); } else { textAlarmStatus .setCompoundDrawablesWithIntrinsicBounds( getResources() .getDrawable( R.drawable.ic_alarm_neutral), null, null, null); textAlarmStatus.setText(result[0]); textAlarmStatusSub .setText(R.string.not_using_smartwake_); } } else { textAlarmStatus .setCompoundDrawablesWithIntrinsicBounds( getResources().getDrawable( R.drawable.ic_alarm_none), null, null, null); textAlarmStatus.setText(R.string.no_alarm); textAlarmStatusSub.setText(R.string.sleep_no_alarm); } } } }.execute(); } public void onServiceDisconnected(ComponentName className) { mMonitoringService = null; } }; }