diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7df4110df..563016f89 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -194,6 +194,22 @@ android:name="android.support.PARENT_ACTIVITY" android:value="nodomain.freeyourgadget.gadgetbridge.ControlCenter" /> + + + + + + diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/BluetoothCommunicationService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/BluetoothCommunicationService.java index e4d39b00e..83a4ae505 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/BluetoothCommunicationService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/BluetoothCommunicationService.java @@ -21,6 +21,7 @@ import android.widget.Toast; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.GBDevice.State; @@ -60,6 +61,7 @@ public class BluetoothCommunicationService extends Service { public static final String ACTION_FETCH_ACTIVITY_DATA = "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.fetch_activity_data"; public static final String ACTION_DISCONNECT = "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.disconnect"; public static final String ACTION_FIND_DEVICE = "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.find_device"; + public static final String ACTION_SET_ALARMS = "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.set_alarms"; public static final String EXTRA_PERFORM_PAIR = "perform_pair"; @@ -265,6 +267,10 @@ public class BluetoothCommunicationService extends Service { startForeground(GB.NOTIFICATION_ID, GB.createNotification(getString(R.string.gadgetbridge_running), this)); mStarted = true; break; + case ACTION_SET_ALARMS: + ArrayList alarms = intent.getParcelableArrayListExtra("alarms"); + mDeviceSupport.onSetAlarms(alarms); + break; } return START_STICKY; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/ControlCenter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/ControlCenter.java index c2f332782..22ca6ede9 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/ControlCenter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/ControlCenter.java @@ -29,6 +29,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Set; +import nodomain.freeyourgadget.gadgetbridge.activities.ConfigureAlarms; import nodomain.freeyourgadget.gadgetbridge.activities.ChartsActivity; import nodomain.freeyourgadget.gadgetbridge.activities.SleepChartActivity; import nodomain.freeyourgadget.gadgetbridge.adapter.GBDeviceAdapter; @@ -230,6 +231,12 @@ public class ControlCenter extends Activity { } }); } + case R.id.controlcenter_configure_alarms: + if (selectedDevice != null) { + Intent startIntent; + startIntent = new Intent(ControlCenter.this, ConfigureAlarms.class); + startActivity(startIntent); + } return true; case R.id.controlcenter_take_screenshot: if (selectedDevice != null) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/EventHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/EventHandler.java index 3f4e76533..78995fd37 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/EventHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/EventHandler.java @@ -2,6 +2,7 @@ package nodomain.freeyourgadget.gadgetbridge; import android.net.Uri; +import java.util.ArrayList; import java.util.UUID; public interface EventHandler { @@ -13,6 +14,8 @@ public interface EventHandler { void onSetTime(long ts); + void onSetAlarms(ArrayList alarms); + void onSetCallState(String number, String name, GBCommand command); void onSetMusicInfo(String artist, String album, String track); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBAlarm.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBAlarm.java new file mode 100644 index 000000000..7c542a4d6 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBAlarm.java @@ -0,0 +1,211 @@ +package nodomain.freeyourgadget.gadgetbridge; + +import android.content.SharedPreferences; +import android.os.Parcel; +import android.os.Parcelable; +import android.preference.PreferenceManager; + +import java.util.Calendar; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import static nodomain.freeyourgadget.gadgetbridge.miband.MiBandConst.PREF_MIBAND_ALARMS; + + +public class GBAlarm implements Parcelable, Comparable { + + private int index; + private boolean enabled; + private boolean smartWakeup; + private int repetition; + private int hour; + private int minute; + + public static final byte ALARM_ONCE = 0; + public static final byte ALARM_MON = 1; + public static final byte ALARM_TUE = 2; + public static final byte ALARM_WED = 4; + public static final byte ALARM_THU = 8; + public static final byte ALARM_FRI = 16; + public static final byte ALARM_SAT = 32; + public static final byte ALARM_SUN = 64; + + public static final String[] DEFAULT_ALARMS = {"2,false,false,0,15,30","1,false,false,96,8,0","0,false,true,31,7,30"}; + + + public GBAlarm(int index, boolean enabled, boolean smartWakeup, byte repetition, int hour, int minute) { + this.index = index; + this.enabled = enabled; + this.smartWakeup = smartWakeup; + this.repetition = repetition; + this.hour = hour; + this.minute = minute; + } + + public GBAlarm(String fromPreferences){ + String[] tokens = fromPreferences.split(","); + //TODO: sanify the string! + this.index = Integer.parseInt(tokens[0]); + this.enabled = Boolean.parseBoolean(tokens[1]); + this.smartWakeup = Boolean.parseBoolean(tokens[2]); + this.repetition = Integer.parseInt(tokens[3]); + this.hour = Integer.parseInt(tokens[4]); + this.minute = Integer.parseInt(tokens[5]); + } + + private static GBAlarm readFromParcel(Parcel pc) { + int index = pc.readInt(); + boolean enabled = Boolean.parseBoolean(pc.readString()); + boolean smartWakeup = Boolean.parseBoolean(pc.readString()); + int repetition = pc.readInt(); + int hour = pc.readInt(); + int minute = pc.readInt(); + return new GBAlarm(index, enabled, smartWakeup, (byte)repetition, hour, minute); + } + + @Override + public boolean equals(Object o) { + if (o instanceof GBAlarm) { + GBAlarm comp = (GBAlarm)o; + return comp.getIndex() == getIndex(); + } else { + return false; + } + } + + @Override + public int hashCode() { + return getIndex(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(this.index); + dest.writeString(String.valueOf(this.enabled)); + dest.writeString(String.valueOf(this.smartWakeup)); + dest.writeInt(this.repetition); + dest.writeInt(this.hour); + dest.writeInt(this.minute); + } + + @Override + public int compareTo(Object another) { + if (this.getIndex() < ((GBAlarm)another).getIndex()) { + return -1; + }else if (this.getIndex() > ((GBAlarm)another).getIndex()) { + return 1; + } + return 0; + } + + public int getIndex() { + return this.index; + } + + public String getTime() { + return String.format("%02d",this.hour) + ":" + String.format("%02d",this.minute); + } + + public int getHour(){ + return this.hour; + } + + public int getMinute(){ + return this.minute; + } + public Calendar getAlarmCal() { + Calendar alarm = Calendar.getInstance(); + alarm.set(Calendar.HOUR_OF_DAY, this.hour); + alarm.set(Calendar.MINUTE, this.minute); + return alarm; + } + + public boolean isEnabled() { + return this.enabled; + } + + public boolean isSmartWakeup() { + return this.smartWakeup; + } + + public boolean getRepetition(int dow) { + return (this.repetition & dow) > 0; + } + + public int getRepetitionMask() { + return this.repetition; + } + + public String toPreferences() { + return String.valueOf(this.index)+','+ + String.valueOf(this.enabled)+','+ + String.valueOf(this.smartWakeup)+','+ + String.valueOf(this.repetition)+','+ + String.valueOf(this.hour)+','+ + String.valueOf(this.minute); + } + + public void setSmartWakeup(boolean smartWakeup) { + this.smartWakeup = smartWakeup; + } + + public void setRepetition(boolean mon, boolean tue, boolean wed, boolean thu, boolean fri, boolean sat, boolean sun) { + this.repetition = ALARM_ONCE | + (mon ? ALARM_MON : 0) | + (tue ? ALARM_TUE : 0) | + (wed ? ALARM_WED : 0) | + (thu ? ALARM_THU : 0) | + (fri ? ALARM_FRI : 0) | + (sat ? ALARM_SAT : 0) | + (sun ? ALARM_SUN : 0); + } + + public void setHour(int hour) { + this.hour = hour; + } + + public void setMinute(int minute) { + this.minute = minute; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public void store() { + SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(GBApplication.getContext()); + Set preferencesAlarmListSet = sharedPrefs.getStringSet(PREF_MIBAND_ALARMS, new HashSet()); + //the old Set cannot be updated in place see http://developer.android.com/reference/android/content/SharedPreferences.html#getStringSet%28java.lang.String,%20java.util.Set%3Cjava.lang.String%3E%29 + Set newPrefs = new HashSet(preferencesAlarmListSet); + + Iterator iterator = newPrefs.iterator(); + + while (iterator.hasNext()) { + String alarmString = iterator.next(); + if(this.equals(new GBAlarm(alarmString))) { + iterator.remove(); + break; + } + } + newPrefs.add(this.toPreferences()); + sharedPrefs.edit().putStringSet(PREF_MIBAND_ALARMS, newPrefs).commit(); + return; + } + + public static final Creator CREATOR = new Creator() { + public GBAlarm createFromParcel(Parcel in) { + return readFromParcel(in); + } + + public GBAlarm[] newArray(int size) { + return new GBAlarm[size]; + } + + }; +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/ServiceDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/ServiceDeviceSupport.java index 9a17893b8..8ea3df39d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/ServiceDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/ServiceDeviceSupport.java @@ -7,6 +7,7 @@ import android.net.Uri; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; import java.util.UUID; /** @@ -226,4 +227,12 @@ public class ServiceDeviceSupport implements DeviceSupport { } delegate.onScreenshotReq(); } + + @Override + public void onSetAlarms(ArrayList alarms) { + if (checkBusy("set alarms")) { + return; + } + delegate.onSetAlarms(alarms); + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AlarmDetails.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AlarmDetails.java new file mode 100644 index 000000000..db8a45bb7 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AlarmDetails.java @@ -0,0 +1,81 @@ +package nodomain.freeyourgadget.gadgetbridge.activities; + +import android.app.Activity; +import android.os.Bundle; +import android.os.Parcelable; +import android.text.format.DateFormat; +import android.view.MenuItem; +import android.widget.CheckBox; +import android.widget.TimePicker; + +import nodomain.freeyourgadget.gadgetbridge.GBAlarm; +import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.R; + +public class AlarmDetails extends Activity { + + private GBAlarm alarm; + private TimePicker timePicker; + private CheckBox cbSmartWakeup; + private CheckBox cbMonday; + private CheckBox cbTuesday; + private CheckBox cbWednesday; + private CheckBox cbThursday; + private CheckBox cbFriday; + private CheckBox cbSaturday; + private CheckBox cbSunday; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_alarm_details); + + Parcelable p = getIntent().getExtras().getParcelable("alarm"); + alarm = (GBAlarm) p; + + timePicker = (TimePicker) findViewById(R.id.alarm_time_picker); + cbSmartWakeup = (CheckBox) findViewById(R.id.alarm_cb_smart_wakeup); + cbMonday = (CheckBox) findViewById(R.id.alarm_cb_mon); + cbTuesday = (CheckBox) findViewById(R.id.alarm_cb_tue); + cbWednesday = (CheckBox) findViewById(R.id.alarm_cb_wed); + cbThursday = (CheckBox) findViewById(R.id.alarm_cb_thu); + cbFriday = (CheckBox) findViewById(R.id.alarm_cb_fri); + cbSaturday = (CheckBox) findViewById(R.id.alarm_cb_sat); + cbSunday = (CheckBox) findViewById(R.id.alarm_cb_sun); + + timePicker.setIs24HourView(DateFormat.is24HourFormat(GBApplication.getContext())); + timePicker.setCurrentHour(alarm.getHour()); + timePicker.setCurrentMinute(alarm.getMinute()); + + cbSmartWakeup.setChecked(alarm.isSmartWakeup()); + + cbMonday.setChecked(alarm.getRepetition(GBAlarm.ALARM_MON)); + cbTuesday.setChecked(alarm.getRepetition(GBAlarm.ALARM_TUE)); + cbWednesday.setChecked(alarm.getRepetition(GBAlarm.ALARM_WED)); + cbThursday.setChecked(alarm.getRepetition(GBAlarm.ALARM_THU)); + cbFriday.setChecked(alarm.getRepetition(GBAlarm.ALARM_FRI)); + cbSaturday.setChecked(alarm.getRepetition(GBAlarm.ALARM_SAT)); + cbSunday.setChecked(alarm.getRepetition(GBAlarm.ALARM_SUN)); + + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + // back button + updateAlarm(); + finish(); + return true; + } + return super.onOptionsItemSelected(item); + } + + private void updateAlarm() { + alarm.setSmartWakeup(cbSmartWakeup.isChecked()); + alarm.setRepetition(cbMonday.isChecked(), cbTuesday.isChecked(), cbWednesday.isChecked(), cbThursday.isChecked(), cbFriday.isChecked(), cbSaturday.isChecked(), cbSunday.isChecked()); + alarm.setHour(timePicker.getCurrentHour()); + alarm.setMinute(timePicker.getCurrentMinute()); + alarm.store(); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ConfigureAlarms.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ConfigureAlarms.java new file mode 100644 index 000000000..ce3c147bc --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ConfigureAlarms.java @@ -0,0 +1,86 @@ +package nodomain.freeyourgadget.gadgetbridge.activities; + +import android.app.ListActivity; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.view.MenuItem; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import nodomain.freeyourgadget.gadgetbridge.BluetoothCommunicationService; +import nodomain.freeyourgadget.gadgetbridge.GBAlarm; +import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.adapter.GBAlarmListAdapter; + +import static nodomain.freeyourgadget.gadgetbridge.miband.MiBandConst.PREF_MIBAND_ALARMS; + + +public class ConfigureAlarms extends ListActivity { + + private GBAlarmListAdapter mGBAlarmListAdapter; + private Set preferencesAlarmListSet; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_configure_alarms); + getActionBar().setDisplayHomeAsUpEnabled(true); + + SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); + preferencesAlarmListSet = sharedPrefs.getStringSet(PREF_MIBAND_ALARMS, new HashSet()); + if (preferencesAlarmListSet.isEmpty()) { + //initialize the preferences + preferencesAlarmListSet = new HashSet<>(Arrays.asList(GBAlarm.DEFAULT_ALARMS)); + sharedPrefs.edit().putStringSet(PREF_MIBAND_ALARMS, preferencesAlarmListSet).commit(); + } + + mGBAlarmListAdapter = new GBAlarmListAdapter(this, preferencesAlarmListSet); + + setListAdapter(mGBAlarmListAdapter); + + } + + @Override + protected void onResume() { + super.onResume(); + + SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); + preferencesAlarmListSet = sharedPrefs.getStringSet(PREF_MIBAND_ALARMS, new HashSet()); + + mGBAlarmListAdapter.setAlarmList(preferencesAlarmListSet); + mGBAlarmListAdapter.notifyDataSetChanged(); + + sendAlarmsToDevice(); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + // back button + sendAlarmsToDevice(); + finish(); + return true; + } + return super.onOptionsItemSelected(item); + } + + public void configureAlarm(GBAlarm alarm) { + Intent startIntent; + startIntent = new Intent(getApplicationContext(), AlarmDetails.class); + startIntent.putExtra("alarm", alarm); + startActivity(startIntent); + } + + private void sendAlarmsToDevice() { + Intent startIntent = new Intent(ConfigureAlarms.this, BluetoothCommunicationService.class); + startIntent.putParcelableArrayListExtra("alarms", mGBAlarmListAdapter.getAlarmList()); + startIntent.setAction(BluetoothCommunicationService.ACTION_SET_ALARMS); + startService(startIntent); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBAlarmListAdapter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBAlarmListAdapter.java new file mode 100644 index 000000000..3abf16221 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBAlarmListAdapter.java @@ -0,0 +1,153 @@ +package nodomain.freeyourgadget.gadgetbridge.adapter; + + +import android.content.Context; +import android.graphics.Color; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.CompoundButton; +import android.widget.Switch; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.Set; + +import nodomain.freeyourgadget.gadgetbridge.GBAlarm; +import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.activities.ConfigureAlarms; + + +public class GBAlarmListAdapter extends ArrayAdapter { + + + private final Context mContext; + private ArrayList alarmList; + + public GBAlarmListAdapter(Context context, ArrayList alarmList) { + super(context, 0, alarmList); + + this.mContext = context; + this.alarmList = alarmList; + } + + public GBAlarmListAdapter(Context context,Set preferencesAlarmListSet) { + super(context, 0, new ArrayList()); + + this.mContext = context; + alarmList = new ArrayList(); + + for (String alarmString : preferencesAlarmListSet) { + alarmList.add(new GBAlarm(alarmString)); + } + + Collections.sort(alarmList); + } + + public void setAlarmList(Set preferencesAlarmListSet) { + alarmList = new ArrayList(); + + for (String alarmString : preferencesAlarmListSet) { + alarmList.add(new GBAlarm(alarmString)); + } + + Collections.sort(alarmList); + } + + public ArrayList getAlarmList() { + return alarmList; + } + + + public void update(GBAlarm alarm) { + for (GBAlarm a : alarmList) { + if(alarm.equals(a)) { + a = alarm; + } + } + alarm.store(); + } + + @Override + public int getCount() { + if (alarmList != null) { + return alarmList.size(); + } + return 0; + } + + @Override + public GBAlarm getItem(int position) { + if (alarmList != null) { + return alarmList.get(position); + } + return null; + } + + @Override + public long getItemId(int position) { + if (alarmList != null) { + return alarmList.get(position).getIndex(); + } + return 0; + } + + @Override + public View getView(int position, View view, ViewGroup parent) { + + final GBAlarm alarm = getItem(position); + + if (view == null) { + LayoutInflater inflater = (LayoutInflater) mContext + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + view = inflater.inflate(R.layout.alarm_item, parent, false); + } + + TextView alarmTime = (TextView) view.findViewById(R.id.alarm_item_time); + Switch isEnabled = (Switch) view.findViewById(R.id.alarm_item_toggle); + TextView isSmartWakeup = (TextView) view.findViewById(R.id.alarm_smart_wakeup); + + highlightDay((TextView) view.findViewById(R.id.alarm_item_sunday), alarm.getRepetition(GBAlarm.ALARM_SUN)); + highlightDay((TextView) view.findViewById(R.id.alarm_item_monday), alarm.getRepetition(GBAlarm.ALARM_MON)); + highlightDay((TextView) view.findViewById(R.id.alarm_item_tuesday), alarm.getRepetition(GBAlarm.ALARM_TUE)); + highlightDay((TextView) view.findViewById(R.id.alarm_item_wednesday), alarm.getRepetition(GBAlarm.ALARM_WED)); + highlightDay((TextView) view.findViewById(R.id.alarm_item_thursday), alarm.getRepetition(GBAlarm.ALARM_THU)); + highlightDay((TextView) view.findViewById(R.id.alarm_item_friday), alarm.getRepetition(GBAlarm.ALARM_FRI)); + highlightDay((TextView) view.findViewById(R.id.alarm_item_saturday), alarm.getRepetition(GBAlarm.ALARM_SAT)); + + isEnabled.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + alarm.setEnabled(isChecked); + update(alarm); + } + }); + + view.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + ((ConfigureAlarms)mContext).configureAlarm(alarm); + } + }); + alarmTime.setText(alarm.getTime()); + isEnabled.setChecked(alarm.isEnabled()); + if(alarm.isSmartWakeup()) { + isSmartWakeup.setVisibility(TextView.VISIBLE); + } else { + isSmartWakeup.setVisibility(TextView.GONE); + } + + return view; + } + + private void highlightDay(TextView view, boolean isOn) { + if (isOn) { + view.setTextColor(Color.BLUE); + } else { + view.setTextColor(Color.BLACK); + } + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/miband/MiBandConst.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/miband/MiBandConst.java index 9754a5fa0..d85cd5ebd 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/miband/MiBandConst.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/miband/MiBandConst.java @@ -15,6 +15,7 @@ public final class MiBandConst { public static final String PREF_USER_WEIGHT_KG = "mi_user_weight_kg"; public static final String PREF_MIBAND_WEARSIDE = "mi_wearside"; public static final String PREF_MIBAND_ADDRESS = "development_miaddr"; // FIXME: should be prefixed mi_ + public static final String PREF_MIBAND_ALARMS = "mi_alarms"; public static final String ORIGIN_SMS = "sms"; public static final String ORIGIN_INCOMING_CALL = "incoming_call"; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/miband/MiBandService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/miband/MiBandService.java index ff53ae32a..e9500f365 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/miband/MiBandService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/miband/MiBandService.java @@ -134,6 +134,9 @@ public class MiBandService { public static final byte COMMAND_CONFIRM_ACTIVITY_DATA_TRANSFER_COMPLETE = 0xa; public static final byte COMMAND_FETCH_DATA = 0x6; + + public static final byte COMMAND_SET_TIMER = 0x4; + /* @@ -152,8 +155,6 @@ public class MiBandService { public static final COMMAND_SET_REALTIME_STEPS_NOTIFICATION = 0x3t - public static final COMMAND_SET_TIMER = 0x4t - public static final COMMAND_SET_WEAR_LOCATION = 0xft public static final COMMAND_STOP_SYNC_DATA = 0x11t diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/miband/MiBandSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/miband/MiBandSupport.java index 40a03fb27..50356f3cf 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/miband/MiBandSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/miband/MiBandSupport.java @@ -6,18 +6,21 @@ import android.content.SharedPreferences; import android.database.sqlite.SQLiteDatabase; import android.net.Uri; import android.preference.PreferenceManager; +import android.widget.Toast; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.text.DateFormat; +import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.GBActivitySample; +import nodomain.freeyourgadget.gadgetbridge.GBAlarm; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.GBCommand; import nodomain.freeyourgadget.gadgetbridge.GBDevice.State; @@ -323,6 +326,22 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { return VibrationProfile.getProfile(profileId, (byte) (repeat & 0xfff)); } + @Override + public void onSetAlarms(ArrayList alarms) { + try { + BluetoothGattCharacteristic characteristic = getCharacteristic(MiBandService.UUID_CHARACTERISTIC_CONTROL_POINT); + TransactionBuilder builder = performInitialized("Set alarm"); + for (GBAlarm alarm : alarms) { + queueAlarm(alarm, builder, characteristic); + } + builder.queue(getQueue()); + Toast.makeText(getContext(), getContext().getString(R.string.user_feedback_miband_set_alarms_ok), Toast.LENGTH_SHORT).show(); + } catch (IOException ex) { + Toast.makeText(getContext(), getContext().getString(R.string.user_feedback_miband_set_alarms_failed), Toast.LENGTH_LONG).show(); + LOG.error("Unable to set alarms on MI device", ex); + } + } + @Override public void onSMS(String from, String body) { performPreferredNotification("sms received", ORIGIN_SMS, null); @@ -544,6 +563,25 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { } } + + private void queueAlarm(GBAlarm alarm, TransactionBuilder builder, BluetoothGattCharacteristic characteristic) { + Calendar alarmCal = alarm.getAlarmCal(); + byte[] alarmMessage = new byte[] { + (byte) MiBandService.COMMAND_SET_TIMER, + (byte) alarm.getIndex(), + (byte) (alarm.isEnabled() ? 1: 0), + (byte) (alarmCal.get(Calendar.YEAR) - 2000), + (byte) alarmCal.get(Calendar.MONTH), + (byte) alarmCal.get(Calendar.DATE), + (byte) alarmCal.get(Calendar.HOUR_OF_DAY), + (byte) alarmCal.get(Calendar.MINUTE), + (byte) alarmCal.get(Calendar.SECOND), + (byte) (alarm.isSmartWakeup() ? 30 : 0), + (byte) alarm.getRepetitionMask() + }; + builder.write(characteristic, alarmMessage); + } + private void handleActivityNotif(byte[] value) { if (value.length == 11) { // byte 0 is the data type: 1 means that each minute is represented by a triplet of bytes diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/pebble/PebbleSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/pebble/PebbleSupport.java index c868adc0a..43b50d967 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/pebble/PebbleSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/pebble/PebbleSupport.java @@ -2,7 +2,10 @@ package nodomain.freeyourgadget.gadgetbridge.pebble; import android.net.Uri; +import java.util.ArrayList; + import nodomain.freeyourgadget.gadgetbridge.AbstractBTDeviceSupport; +import nodomain.freeyourgadget.gadgetbridge.GBAlarm; import nodomain.freeyourgadget.gadgetbridge.GBDeviceIoThread; import nodomain.freeyourgadget.gadgetbridge.protocol.GBDeviceProtocol; @@ -38,4 +41,9 @@ public class PebbleSupport extends AbstractBTDeviceSupport { public synchronized PebbleIoThread getDeviceIOThread() { return (PebbleIoThread) super.getDeviceIOThread(); } + + @Override + public void onSetAlarms(ArrayList alarms) { + //nothing to do ATM + } } diff --git a/app/src/main/res/layout/activity_alarm_details.xml b/app/src/main/res/layout/activity_alarm_details.xml new file mode 100644 index 000000000..3a4d36d05 --- /dev/null +++ b/app/src/main/res/layout/activity_alarm_details.xml @@ -0,0 +1,251 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_configure_alarms.xml b/app/src/main/res/layout/activity_configure_alarms.xml new file mode 100644 index 000000000..3dd725a24 --- /dev/null +++ b/app/src/main/res/layout/activity_configure_alarms.xml @@ -0,0 +1,16 @@ + + + + diff --git a/app/src/main/res/layout/alarm_item.xml b/app/src/main/res/layout/alarm_item.xml new file mode 100644 index 000000000..6bfa02f7d --- /dev/null +++ b/app/src/main/res/layout/alarm_item.xml @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/controlcenter_context.xml b/app/src/main/res/menu/controlcenter_context.xml index 4002869d4..c9c07d963 100644 --- a/app/src/main/res/menu/controlcenter_context.xml +++ b/app/src/main/res/menu/controlcenter_context.xml @@ -6,6 +6,9 @@ + diff --git a/app/src/main/res/menu/menu_alarm_details.xml b/app/src/main/res/menu/menu_alarm_details.xml new file mode 100644 index 000000000..14e9fe768 --- /dev/null +++ b/app/src/main/res/menu/menu_alarm_details.xml @@ -0,0 +1,7 @@ + + + diff --git a/app/src/main/res/menu/menu_set_alarm.xml b/app/src/main/res/menu/menu_set_alarm.xml new file mode 100644 index 000000000..835ed8d52 --- /dev/null +++ b/app/src/main/res/menu/menu_set_alarm.xml @@ -0,0 +1,7 @@ + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e9bfccd75..b1685f25f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -138,5 +138,17 @@ Find lost Device Cancel to stop vibration. ChartsActivity - + Configure Alarms + Configure alarms + Alarm Details + Sun + Mon + Tue + Wed + Thu + Fri + Sat + smart wakeup + There was an error setting the alarms, please try again! + Alarms sent to device!