package com.hairysoft.cockcrow; import android.animation.Animator; import android.animation.ValueAnimator; import android.app.Activity; import android.app.AlarmManager; import android.app.DialogFragment; import android.app.PendingIntent; import android.bluetooth.BluetoothAdapter; // import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.media.RingtoneManager; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Message; import com.hairysoft.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.animation.AccelerateDecelerateInterpolator; import android.widget.AnalogClock; import android.widget.ImageButton; import android.widget.SeekBar; import android.widget.TextView; // import android.widget.Toast; import com.hairysoft.alarm.AlarmActivity; import com.hairysoft.alarm.AlarmReceiver; import com.hairysoft.bt.ConnectThread; import com.hairysoft.bt.Dispatcher; import com.hairysoft.message.BaseMessage; import com.hairysoft.message.ClockMessage; import com.hairysoft.message.DemoSunrise; import com.hairysoft.message.SetAlarm; import com.hairysoft.message.SetBrightness; import com.hairysoft.message.TurnOnOff; import com.hairysoft.util.Constants; import org.json.JSONException; import java.util.Calendar; /** * Main activity for the application */ public class MainActivity extends Activity implements TimePickerFragment.OnAlarmSelectedListener { private final static String TAG = "MainActivity"; // The views used with a global scope private AnalogClock analogClock; private TextView alarmTimeView; private TextView alarmButtonText; private TextView connStatus; // Preferences private String alarmTime; private String notySoundUri; private SharedPreferences prefs; // Bluetooth connection handlers private BluetoothAdapter mBluetoothAdapter; private WakyBluetoothService wakyBluetoothService; // Alarm handlers private AlarmManager mAlarmManager; private Intent mNotificationReceiverIntent; private PendingIntent mNotificationReceiverPendingIntent; private boolean sliderAnimating = false; // Handler to receive notifications from other places within the application, and show/handle them in the UI thread private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { // Context c = getApplicationContext(); switch (msg.what) { case Constants.BT_CONNECT_SUCCESS: // Toast.makeText(c, R.string.connect_success, Toast.LENGTH_LONG).show(); connStatus.setText(R.string.connected); break; case Constants.BT_CONNECT_FAILED: // Toast.makeText(c, R.string.connect_failed, Toast.LENGTH_LONG).show(); connStatus.setText(R.string.cant_connect); wakyBluetoothService.discoverWaky(true); break; case Constants.BT_DISCONNECT: connStatus.setText(R.string.disconnected); wakyBluetoothService.discoverWaky(true); break; case Constants.UPDATE_ALARM: if(alarmTime != null && alarmTime.length() > 0) { String[] items = alarmTime.split(":"); int hourOfDay = Integer.parseInt(items[0]); int minute = Integer.parseInt(items[1]); try { Dispatcher.queueMessage(new SetAlarm(hourOfDay, minute).getJSON()); } catch(JSONException ex) { } } break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initApp(); initGUI(); // Register the types of messages to be recognized by the application // More information in BaseMessage.java BaseMessage.registerClass(ClockMessage.class, SetBrightness.class, DemoSunrise.class, SetAlarm.class, TurnOnOff.class); mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); wakyBluetoothService = new WakyBluetoothService(this, mHandler); Dispatcher.init(); mAlarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); mNotificationReceiverIntent = new Intent(this, AlarmReceiver.class); mNotificationReceiverPendingIntent = PendingIntent.getBroadcast(this, 0, mNotificationReceiverIntent, 0); } @Override protected void onStart() { super.onStart(); if(!ConnectThread.isConnected()) { if (mBluetoothAdapter == null) { // This should not happen, though mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); } if (!mBluetoothAdapter.isEnabled()) { Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableIntent, Constants.AR_REQUEST_ENABLE_BT); } else { wakyBluetoothService.discoverWaky(); } } else { connStatus.setText(R.string.connected); } } @Override protected void onStop() { super.onStop(); wakyBluetoothService.holdWaky(); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case Constants.AR_REQUEST_ENABLE_BT: if(resultCode == Activity.RESULT_OK) { wakyBluetoothService.discoverWaky(); } else { Log.d(TAG, "BT not enabled"); // Toast.makeText(this, R.string.bt_not_enabled, Toast.LENGTH_LONG).show(); } break; case Constants.AR_SELECT_ALARMTONE: Uri uri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI); if(uri != null) { String name = RingtoneManager.getRingtone(this, uri).getTitle(this); Log.d(TAG, "Selected sound: " + name + " (" + uri.toString() + ")"); alarmButtonText.setText(name); SharedPreferences.Editor editor = prefs.edit(); editor.putString("noty_sound_uri", uri.toString()); editor.putString("noty_sound_name", name); editor.commit(); } break; } } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == R.id.action_add_alarm) { Log.d(TAG, "Adding alarm"); DialogFragment timePicker = new TimePickerFragment(); timePicker.show(getFragmentManager(), "timePicker"); return true; } else if(id == R.id.action_search_waky) { Log.d(TAG, "Searching for waky"); if(!ConnectThread.isConnected()) { wakyBluetoothService.discoverWaky(true); } return true; } else if(id == R.id.action_demo) { Log.d(TAG, "Demoing sunrise"); try { Dispatcher.queueMessage(new DemoSunrise().getJSON()); } catch(JSONException ex) { } return true; } else if(id == R.id.action_demo_alarm) { startActivity(new Intent(this, AlarmActivity.class)); } return super.onOptionsItemSelected(item); } @Override public void onAlarmSelected(int hourOfDay, int minute) { String timeString = hourOfDay+":"+(minute < 10 ? "0" : "")+minute; SharedPreferences.Editor editor = prefs.edit(); editor.putString("alarm_time", timeString); editor.commit(); alarmTimeView.setText(timeString); alarmTime = timeString; Calendar c = Calendar.getInstance(); c.set(Calendar.HOUR_OF_DAY, hourOfDay); c.set(Calendar.MINUTE, minute); if(c.getTimeInMillis() < System.currentTimeMillis()) { c.add(Calendar.DATE, 1); } mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(), mNotificationReceiverPendingIntent); try { Dispatcher.queueMessage(new SetAlarm(hourOfDay, minute).getJSON()); } catch(JSONException ex) { } } private void initApp() { prefs = getSharedPreferences(Constants.PREFS_NAME, MODE_PRIVATE); alarmTime = prefs.getString("alarm_time", null); notySoundUri = prefs.getString("noty_sound_uri", null); } private void initGUI() { /* AnalogClock */ analogClock = (AnalogClock) findViewById(R.id.analogClock); /* SeekBar - Set current brightness */ final SeekBar seekBar = (SeekBar) findViewById(R.id.seekBar); seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int i, boolean b) { // Checking if the progress is changing due to an animation, in order to avoid flooding the bluetooth channel with unnecessary messages if(!sliderAnimating) { Log.d(TAG, "Setting brightness @ " + i); try { Dispatcher.queueMessage(new SetBrightness(i).getJSON()); } catch(JSONException ex) { } } } @Override public void onStartTrackingTouch(SeekBar seekBar) { // Not implemented } @Override public void onStopTrackingTouch(SeekBar seekBar) { // Not implemented } }); /* Value animator end listener */ final Animator.AnimatorListener animatorListener = new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animator) { sliderAnimating = true; } @Override public void onAnimationEnd(Animator animator) { sliderAnimating = false; if(seekBar.getProgress() == 0) { Log.d(TAG, "Leds turned off"); } else if(seekBar.getProgress() == seekBar.getMax()) { Log.d(TAG, "Leds set at full brightness"); } try { Dispatcher.queueMessage(new TurnOnOff(seekBar.getProgress() > seekBar.getMax() - 1).getJSON()); } catch(JSONException ex) { } } @Override public void onAnimationCancel(Animator animator) { // Not implemented } @Override public void onAnimationRepeat(Animator animator) { // Not implemented } }; /* Alarm time view */ alarmTimeView = (TextView) findViewById(R.id.alarmTime); alarmTimeView.setText(alarmTime == null ? "--:--" : alarmTime); alarmTimeView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.d(TAG, "Adding alarm"); DialogFragment timePicker = new TimePickerFragment(); timePicker.show(getFragmentManager(), "timePicker"); } }); /* Power off leds */ ImageButton powerOff = (ImageButton) findViewById(R.id.powerOff); powerOff.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Log.d(TAG, "Powering leds off"); ValueAnimator anim = ValueAnimator.ofInt(seekBar.getProgress(), 0); anim.setDuration(500); anim.addListener(animatorListener); anim.setInterpolator(new AccelerateDecelerateInterpolator()); anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { seekBar.setProgress((Integer)valueAnimator.getAnimatedValue()); } }); anim.start(); } }); /* Leds full brightness */ ImageButton powerOn = (ImageButton) findViewById(R.id.powerOn); powerOn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Log.d(TAG, "Settings leds to full brightness"); ValueAnimator anim = ValueAnimator.ofInt(seekBar.getProgress(), seekBar.getMax()); anim.setDuration(500); anim.addListener(animatorListener); anim.setInterpolator(new AccelerateDecelerateInterpolator()); anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { seekBar.setProgress((Integer)valueAnimator.getAnimatedValue()); } }); anim.start(); } }); /* Remove alarm */ ImageButton removeAlarm = (ImageButton) findViewById(R.id.deleteAlarm); removeAlarm.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.d(TAG, "Removing alarm"); SharedPreferences.Editor editor = prefs.edit(); editor.remove("alarm_time"); editor.commit(); alarmTimeView.setText("--:--"); mAlarmManager.cancel(mNotificationReceiverPendingIntent); try { Dispatcher.queueMessage(new SetAlarm(-1, -1).getJSON()); } catch(JSONException ex) { } } }); /* Connection status */ connStatus = (TextView) findViewById(R.id.connStatus); /* Ringtone selection */ View.OnClickListener selectRingTone = new View.OnClickListener() { @Override public void onClick(View v) { Intent sound = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER); sound.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_ALARM); if(notySoundUri != null) { sound.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, Uri.parse(notySoundUri)); } startActivityForResult(sound, Constants.AR_SELECT_ALARMTONE); } }; ImageButton alarmButtonImage = (ImageButton) findViewById(R.id.alarmTone); alarmButtonImage.setOnClickListener(selectRingTone); alarmButtonText = (TextView) findViewById(R.id.alarmRingtone); alarmButtonText.setOnClickListener(selectRingTone); alarmButtonText.setText(prefs.getString("noty_sound_name", "Default ringtone")); } }