2021-01-10 23:37:09 +01:00
/ * Copyright ( C ) 2019 - 2021 Andreas Shimokawa , Daniel Dakhno
This file is part of Gadgetbridge .
Gadgetbridge is free software : you can redistribute it and / or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
Gadgetbridge 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 Affero General Public License for more details .
You should have received a copy of the GNU Affero General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>. */
2019-12-31 03:14:20 +01:00
package nodomain.freeyourgadget.gadgetbridge.devices.qhybrid ;
2023-07-22 21:23:27 +02:00
import static nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSupport.QHYBRID_COMMAND_UPDATE_WIDGETS ;
2019-12-31 03:14:20 +01:00
import android.content.DialogInterface ;
import android.content.Intent ;
import android.content.SharedPreferences ;
2020-04-08 02:12:14 +02:00
import android.net.Uri ;
2019-12-31 03:14:20 +01:00
import android.os.Bundle ;
2020-01-19 04:01:57 +01:00
import android.util.SparseArray ;
2019-12-31 03:14:20 +01:00
import android.view.View ;
import android.view.ViewGroup ;
import android.widget.AdapterView ;
import android.widget.ArrayAdapter ;
import android.widget.ListView ;
import android.widget.TextView ;
2020-03-01 22:20:00 +01:00
import android.widget.Toast ;
2019-12-31 03:14:20 +01:00
import androidx.annotation.NonNull ;
import androidx.annotation.Nullable ;
import androidx.localbroadcastmanager.content.LocalBroadcastManager ;
2023-07-22 21:23:27 +02:00
import com.google.android.material.dialog.MaterialAlertDialogBuilder ;
2019-12-31 03:14:20 +01:00
import org.json.JSONArray ;
import org.json.JSONException ;
2020-01-19 04:01:57 +01:00
import org.json.JSONObject ;
2019-12-31 03:14:20 +01:00
import java.util.ArrayList ;
2020-01-19 04:01:57 +01:00
import java.util.Iterator ;
2019-12-31 03:14:20 +01:00
import java.util.List ;
import nodomain.freeyourgadget.gadgetbridge.GBApplication ;
import nodomain.freeyourgadget.gadgetbridge.R ;
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBActivity ;
2022-06-14 18:05:41 +02:00
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice ;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType ;
2019-12-31 03:14:20 +01:00
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSupport ;
2020-01-19 04:01:57 +01:00
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget.CustomBackgroundWidgetElement ;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget.CustomTextWidgetElement ;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget.CustomWidget ;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget.CustomWidgetElement ;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget.Widget ;
2021-03-11 17:19:31 +01:00
import nodomain.freeyourgadget.gadgetbridge.util.GB ;
import nodomain.freeyourgadget.gadgetbridge.util.Version ;
2020-01-19 04:01:57 +01:00
2021-05-29 16:42:32 +02:00
public class HRConfigActivity extends AbstractGBActivity {
2019-12-31 03:14:20 +01:00
private SharedPreferences sharedPreferences ;
2020-01-19 04:01:57 +01:00
private WidgetListAdapter widgetListAdapter ;
private ArrayList < CustomWidget > customWidgets = new ArrayList < > ( ) ;
SparseArray < String > widgetButtonsMapping = new SparseArray < > ( 4 ) ;
2019-12-31 03:14:20 +01:00
2020-04-08 02:12:14 +02:00
private static final int REQUEST_CODE_WIDGET_EDIT = 0 ;
private static final int REQUEST_CODE_IMAGE_PICK = 1 ;
private static final int REQUEST_CODE_IMAGE_EDIT = 2 ;
2019-12-31 03:14:20 +01:00
@Override
protected void onCreate ( Bundle savedInstanceState ) {
super . onCreate ( savedInstanceState ) ;
setContentView ( R . layout . activity_qhybrid_hr_settings ) ;
sharedPreferences = GBApplication . getPrefs ( ) . getPreferences ( ) ;
2020-01-19 04:01:57 +01:00
initMappings ( ) ;
loadWidgetConfigs ( ) ;
final ListView widgetListView = findViewById ( R . id . qhybrid_widget_list ) ;
widgetListAdapter = new WidgetListAdapter ( customWidgets ) ;
widgetListView . setAdapter ( widgetListAdapter ) ;
widgetListView . setOnItemClickListener ( new AdapterView . OnItemClickListener ( ) {
@Override
public void onItemClick ( AdapterView < ? > parent , View view , int position , long id ) {
Widget widget = widgetListAdapter . getItem ( position ) ;
Intent startIntent = new Intent ( HRConfigActivity . this , WidgetSettingsActivity . class ) ;
startIntent . putExtra ( " EXTRA_WIDGET " , widget ) ;
startIntent . putExtra ( " EXTRA_WIDGET_IDNEX " , position ) ;
2020-04-24 01:49:42 +02:00
startIntent . putExtra ( " EXTRA_WIDGET_INITIAL_NAME " , ( ( CustomWidget ) widget ) . getName ( ) ) ;
2020-01-19 04:01:57 +01:00
2020-04-08 02:12:14 +02:00
startActivityForResult ( startIntent , REQUEST_CODE_WIDGET_EDIT ) ;
2020-01-19 04:01:57 +01:00
}
} ) ;
loadCustomWidgetList ( ) ;
findViewById ( R . id . qhybrid_widget_add ) . setOnClickListener ( new View . OnClickListener ( ) {
@Override
public void onClick ( View v ) {
Intent startIntent = new Intent ( HRConfigActivity . this , WidgetSettingsActivity . class ) ;
2020-04-08 02:12:14 +02:00
startActivityForResult ( startIntent , REQUEST_CODE_WIDGET_EDIT ) ;
}
} ) ;
findViewById ( R . id . qhybrid_set_background ) . setOnClickListener ( new View . OnClickListener ( ) {
@Override
public void onClick ( View view ) {
2023-07-22 21:23:27 +02:00
new MaterialAlertDialogBuilder ( HRConfigActivity . this )
2020-04-08 02:12:14 +02:00
. setTitle ( " whoop whoop " )
. setMessage ( " background has to be pushed every time a custom widget changes, causing traffic and battery drain. Consider that when using custom widgets. " )
. setPositiveButton ( " ok " , new DialogInterface . OnClickListener ( ) {
@Override
public void onClick ( DialogInterface dialogInterface , int i ) {
Intent pickIntent = new Intent ( Intent . ACTION_PICK ) ;
pickIntent . setType ( " image/* " ) ;
startActivityForResult ( pickIntent , REQUEST_CODE_IMAGE_PICK ) ;
}
} )
. setNegativeButton ( " nah " , null )
. show ( ) ;
2020-01-19 04:01:57 +01:00
}
} ) ;
2020-04-08 03:20:39 +02:00
findViewById ( R . id . qhybrid_unset_background ) . setOnClickListener ( new View . OnClickListener ( ) {
@Override
public void onClick ( View view ) {
Intent intent = new Intent ( QHybridSupport . QHYBRID_COMMAND_SET_BACKGROUND_IMAGE ) ;
intent . putIntegerArrayListExtra ( " EXTRA_PIXELS " , null ) ;
LocalBroadcastManager . getInstance ( HRConfigActivity . this ) . sendBroadcast ( intent ) ;
}
} ) ;
2020-01-19 04:01:57 +01:00
for ( int i = 0 ; i < widgetButtonsMapping . size ( ) ; i + + ) {
final int widgetButtonId = widgetButtonsMapping . keyAt ( i ) ;
findViewById ( widgetButtonId ) . setOnClickListener ( new View . OnClickListener ( ) {
@Override
public void onClick ( View v ) {
Widget . WidgetType [ ] types = Widget . WidgetType . values ( ) ;
final ArrayList < String > names = new ArrayList < > ( types . length ) ;
for ( Widget . WidgetType type : types ) {
names . add ( getResources ( ) . getString ( type . getStringResource ( ) ) ) ;
}
for ( CustomWidget customWidget : customWidgets ) {
names . add ( customWidget . getName ( ) ) ;
}
final String [ ] nameStrings = names . toArray ( new String [ 0 ] ) ;
2023-07-22 21:23:27 +02:00
new MaterialAlertDialogBuilder ( HRConfigActivity . this )
2020-01-19 04:01:57 +01:00
. setItems (
nameStrings ,
new DialogInterface . OnClickListener ( ) {
@Override
public void onClick ( DialogInterface dialog , int which ) {
saveWidgetSetting ( widgetButtonId , which , nameStrings ) ;
}
}
)
. show ( ) ;
}
} ) ;
}
2021-03-11 17:19:31 +01:00
// Disable some functions on watches with too new firmware (from official app 4.6.0 and higher)
2022-06-14 18:05:41 +02:00
List < GBDevice > devices = GBApplication . app ( ) . getDeviceManager ( ) . getSelectedDevices ( ) ;
2022-08-07 00:17:42 +02:00
for ( GBDevice device : devices ) {
if ( device . getType ( ) = = DeviceType . FOSSILQHYBRID ) {
2022-08-27 02:54:56 +02:00
String fwVersion_str = device . getFirmwareVersion2 ( ) ;
2022-06-14 18:05:41 +02:00
Version fwVersion = new Version ( fwVersion_str ) ;
2022-08-07 00:17:42 +02:00
if ( fwVersion . compareTo ( new Version ( " 2.20 " ) ) > = 0 ) {
2022-06-14 18:05:41 +02:00
findViewById ( R . id . qhybrid_widget_add ) . setEnabled ( false ) ;
for ( int i = 0 ; i < widgetButtonsMapping . size ( ) ; i + + ) {
final int widgetButtonId = widgetButtonsMapping . keyAt ( i ) ;
findViewById ( widgetButtonId ) . setEnabled ( false ) ;
}
findViewById ( R . id . qhybrid_set_background ) . setEnabled ( false ) ;
findViewById ( R . id . qhybrid_unset_background ) . setEnabled ( false ) ;
GB . toast ( getString ( R . string . fossil_hr_warning_firmware_too_new ) , Toast . LENGTH_LONG , GB . INFO ) ;
}
2021-03-11 17:19:31 +01:00
}
}
2022-06-14 18:05:41 +02:00
2019-12-31 03:14:20 +01:00
}
2020-01-19 04:01:57 +01:00
@Override
protected void onActivityResult ( int requestCode , int resultCode , @Nullable Intent data ) {
super . onActivityResult ( requestCode , resultCode , data ) ;
if ( data = = null ) return ;
2020-04-08 02:12:14 +02:00
if ( requestCode = = REQUEST_CODE_WIDGET_EDIT ) {
if ( resultCode = = WidgetSettingsActivity . RESULT_CODE_WIDGET_CREATED ) {
CustomWidget widget = ( CustomWidget ) data . getExtras ( ) . get ( " EXTRA_WIDGET " ) ;
this . customWidgets . add ( widget ) ;
refreshWidgetList ( ) ;
saveCustomWidgetList ( ) ;
2020-01-19 04:01:57 +01:00
2020-04-08 02:12:14 +02:00
LocalBroadcastManager . getInstance ( HRConfigActivity . this ) . sendBroadcast ( new Intent ( QHYBRID_COMMAND_UPDATE_WIDGETS ) ) ;
} else if ( resultCode = = WidgetSettingsActivity . RESULT_CODE_WIDGET_UPDATED ) {
CustomWidget widget = ( CustomWidget ) data . getExtras ( ) . get ( " EXTRA_WIDGET " ) ;
int updateIndex = data . getIntExtra ( " EXTRA_WIDGET_IDNEX " , - 1 ) ;
2020-01-19 04:01:57 +01:00
2020-04-24 01:49:42 +02:00
String initialName = data . getStringExtra ( " EXTRA_WIDGET_INITIAL_NAME " ) ;
String newName = widget . getName ( ) ;
String widgetJSON = sharedPreferences . getString ( " FOSSIL_HR_WIDGETS " , " {} " ) ;
widgetJSON = widgetJSON . replace ( " custom_ " + initialName , " custom_ " + newName ) ;
sharedPreferences . edit ( ) . putString ( " FOSSIL_HR_WIDGETS " , widgetJSON ) . apply ( ) ;
2020-04-08 02:12:14 +02:00
this . customWidgets . set ( updateIndex , widget ) ;
2020-01-19 04:01:57 +01:00
2020-04-24 01:49:42 +02:00
loadWidgetConfigs ( ) ;
2020-04-08 02:12:14 +02:00
refreshWidgetList ( ) ;
saveCustomWidgetList ( ) ;
2020-01-19 04:01:57 +01:00
2020-04-08 02:12:14 +02:00
LocalBroadcastManager . getInstance ( HRConfigActivity . this ) . sendBroadcast ( new Intent ( QHYBRID_COMMAND_UPDATE_WIDGETS ) ) ;
} else if ( resultCode = = WidgetSettingsActivity . RESULT_CODE_WIDGET_DELETED ) {
int updateIndex = data . getIntExtra ( " EXTRA_WIDGET_IDNEX " , - 1 ) ;
2020-01-19 04:01:57 +01:00
2020-04-08 02:12:14 +02:00
this . customWidgets . remove ( updateIndex ) ;
2020-01-19 04:01:57 +01:00
2020-04-08 02:12:14 +02:00
refreshWidgetList ( ) ;
saveCustomWidgetList ( ) ;
2020-01-19 04:01:57 +01:00
2020-04-08 02:12:14 +02:00
LocalBroadcastManager . getInstance ( HRConfigActivity . this ) . sendBroadcast ( new Intent ( QHYBRID_COMMAND_UPDATE_WIDGETS ) ) ;
}
} else if ( requestCode = = REQUEST_CODE_IMAGE_PICK ) {
if ( resultCode = = RESULT_OK )
{
Uri imageUri = data . getData ( ) ;
Intent activityIntent = new Intent ( ) ;
activityIntent . setClass ( this , ImageEditActivity . class ) ;
activityIntent . setData ( imageUri ) ;
startActivityForResult ( activityIntent , REQUEST_CODE_IMAGE_EDIT ) ;
}
} else if ( requestCode = = REQUEST_CODE_IMAGE_EDIT ) {
if ( resultCode = = ImageEditActivity . RESULT_CODE_EDIT_SUCCESS ) {
data . setAction ( QHybridSupport . QHYBRID_COMMAND_SET_BACKGROUND_IMAGE ) ;
LocalBroadcastManager . getInstance ( this ) . sendBroadcast ( data ) ;
}
2020-01-19 04:01:57 +01:00
}
}
private void saveCustomWidgetList ( ) {
try {
JSONArray widgetArray = new JSONArray ( ) ;
for ( CustomWidget widget : customWidgets ) {
JSONArray elementArray = new JSONArray ( ) ;
for ( CustomWidgetElement element : widget . getElements ( ) ) {
JSONObject elementObject = new JSONObject ( ) ;
elementObject
. put ( " type " , element . getWidgetElementType ( ) . getJsonIdentifier ( ) )
. put ( " id " , element . getId ( ) )
. put ( " value " , element . getValue ( ) )
. put ( " x " , element . getX ( ) )
. put ( " y " , element . getY ( ) ) ;
elementArray . put ( elementObject ) ;
}
JSONObject widgetObject = new JSONObject ( ) ;
widgetObject
. put ( " name " , widget . getName ( ) )
. put ( " elements " , elementArray ) ;
widgetArray . put ( widgetObject ) ;
}
sharedPreferences . edit ( ) . putString ( " QHYBRID_CUSTOM_WIDGETS " , widgetArray . toString ( ) ) . apply ( ) ;
} catch ( JSONException e ) {
e . printStackTrace ( ) ;
}
}
private void loadCustomWidgetList ( ) {
String customWidgetJson = sharedPreferences . getString ( " QHYBRID_CUSTOM_WIDGETS " , " [] " ) ;
try {
JSONArray customWidgets = new JSONArray ( customWidgetJson ) ;
this . customWidgets . clear ( ) ;
for ( int i = 0 ; i < customWidgets . length ( ) ; i + + ) {
JSONObject customWidgetObject = customWidgets . getJSONObject ( i ) ;
CustomWidget widget = new CustomWidget (
2020-04-08 02:18:13 +02:00
customWidgetObject . getString ( " name " ) , 0 , 0 , " default " // FIXME: handle force white background
2020-01-19 04:01:57 +01:00
) ;
JSONArray elements = customWidgetObject . getJSONArray ( " elements " ) ;
for ( int i2 = 0 ; i2 < elements . length ( ) ; i2 + + ) {
JSONObject element = elements . getJSONObject ( i2 ) ;
if ( element . getString ( " type " ) . equals ( " text " ) ) {
widget . addElement ( new CustomTextWidgetElement (
element . getString ( " id " ) ,
element . getString ( " value " ) ,
element . getInt ( " x " ) ,
element . getInt ( " y " )
) ) ;
} else if ( element . getString ( " type " ) . equals ( " background " ) ) {
widget . addElement ( new CustomBackgroundWidgetElement (
element . getString ( " id " ) ,
element . getString ( " value " )
) ) ;
}
}
this . customWidgets . add ( widget ) ;
}
refreshWidgetList ( ) ;
} catch ( JSONException e ) {
e . printStackTrace ( ) ;
}
}
private void refreshWidgetList ( ) {
widgetListAdapter . notifyDataSetChanged ( ) ;
}
private void saveWidgetSetting ( int buttonId , int option , String [ ] names ) {
String jsonKey = widgetButtonsMapping . get ( buttonId ) ;
Widget . WidgetType [ ] types = Widget . WidgetType . values ( ) ;
String identifier = null ;
if ( option < types . length ) {
Widget . WidgetType type = types [ option ] ;
identifier = type . getIdentifier ( ) ;
} else {
identifier = " custom_ " + names [ option ] ;
}
try {
JSONObject keyConfig = new JSONObject ( sharedPreferences . getString ( " FOSSIL_HR_WIDGETS " , " {} " ) ) ;
if ( identifier ! = null ) {
keyConfig . put ( jsonKey , identifier ) ;
} else {
keyConfig . remove ( jsonKey ) ;
}
sharedPreferences . edit ( ) . putString ( " FOSSIL_HR_WIDGETS " , keyConfig . toString ( ) ) . apply ( ) ;
LocalBroadcastManager . getInstance ( this ) . sendBroadcast ( new Intent ( QHYBRID_COMMAND_UPDATE_WIDGETS ) ) ;
loadWidgetConfigs ( ) ;
} catch ( JSONException e ) {
e . printStackTrace ( ) ;
}
}
private void loadWidgetConfigs ( ) {
try {
for ( int i = 0 ; i < widgetButtonsMapping . size ( ) ; i + + ) {
( ( TextView ) findViewById ( widgetButtonsMapping . keyAt ( i ) ) ) . setText ( widgetButtonsMapping . valueAt ( i ) + " widget " ) ;
}
JSONObject keyConfig = new JSONObject ( sharedPreferences . getString ( " FOSSIL_HR_WIDGETS " , " {} " ) ) ;
Iterator < String > keyIterator = keyConfig . keys ( ) ;
loop :
while ( keyIterator . hasNext ( ) ) {
String position = keyIterator . next ( ) ;
for ( int widgetButtonIndex = 0 ; widgetButtonIndex < widgetButtonsMapping . size ( ) ; widgetButtonIndex + + ) {
if ( position . equals ( widgetButtonsMapping . valueAt ( widgetButtonIndex ) ) ) {
int buttonId = widgetButtonsMapping . keyAt ( widgetButtonIndex ) ;
String function = keyConfig . getString ( position ) ;
Widget . WidgetType [ ] types = Widget . WidgetType . values ( ) ;
if ( function . startsWith ( " custom_ " ) ) {
( ( TextView ) findViewById ( buttonId ) ) . setText (
position + " widget: " + function . substring ( 7 )
) ;
continue loop ;
}
for ( int widgetIdIndex = 0 ; widgetIdIndex < types . length ; widgetIdIndex + + ) {
String widgetIdMappingValue = types [ widgetIdIndex ] . getIdentifier ( ) ;
if ( widgetIdMappingValue ! = null & & widgetIdMappingValue . equals ( function ) ) {
( ( TextView ) findViewById ( buttonId ) ) . setText (
position + " widget: "
+ getResources ( ) . getText (
types [ widgetIdIndex ] . getStringResource ( )
)
) ;
break ;
}
}
}
}
}
} catch ( JSONException e ) {
e . printStackTrace ( ) ;
}
}
private void initMappings ( ) {
widgetButtonsMapping . put ( R . id . qhybrid_button_widget_top , " top " ) ;
widgetButtonsMapping . put ( R . id . qhybrid_button_widget_right , " right " ) ;
widgetButtonsMapping . put ( R . id . qhybrid_button_widget_bottom , " bottom " ) ;
widgetButtonsMapping . put ( R . id . qhybrid_button_widget_left , " left " ) ;
}
class WidgetListAdapter extends ArrayAdapter < CustomWidget > {
public WidgetListAdapter ( @NonNull List < CustomWidget > objects ) {
super ( HRConfigActivity . this , 0 , objects ) ;
}
@NonNull
@Override
public View getView ( int position , @Nullable View convertView , @NonNull ViewGroup parent ) {
if ( convertView = = null ) convertView = new TextView ( getContext ( ) ) ;
TextView view = ( TextView ) convertView ;
view . setText ( getItem ( position ) . getName ( ) ) ;
// view.setTextColor(Color.WHITE);
view . setTextSize ( 25 ) ;
return view ;
}
}
2019-12-31 03:14:20 +01:00
}