2021-01-10 23:37:09 +01:00
/ * Copyright ( C ) 2020 - 2021 Andreas Shimokawa
2020-04-10 00:48:46 +02:00
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/>. */
package nodomain.freeyourgadget.gadgetbridge.devices.qhybrid ;
import android.content.Context ;
2021-05-29 16:42:32 +02:00
import android.content.Intent ;
2021-06-20 14:17:18 +02:00
import android.graphics.Bitmap ;
2020-04-10 00:48:46 +02:00
import android.net.Uri ;
2021-05-29 16:42:32 +02:00
import androidx.localbroadcastmanager.content.LocalBroadcastManager ;
import org.json.JSONException ;
import org.json.JSONObject ;
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
import java.io.BufferedWriter ;
import java.io.File ;
2021-06-20 14:17:18 +02:00
import java.io.FileOutputStream ;
2021-05-29 16:42:32 +02:00
import java.io.FileWriter ;
2020-04-10 00:48:46 +02:00
import java.io.IOException ;
2021-05-29 16:42:32 +02:00
import java.io.Writer ;
2020-04-10 00:48:46 +02:00
import nodomain.freeyourgadget.gadgetbridge.R ;
import nodomain.freeyourgadget.gadgetbridge.activities.InstallActivity ;
2021-05-29 16:42:32 +02:00
import nodomain.freeyourgadget.gadgetbridge.activities.appmanager.AbstractAppManagerFragment ;
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator ;
2020-04-10 00:48:46 +02:00
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler ;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice ;
2021-05-29 16:42:32 +02:00
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp ;
2020-04-10 00:48:46 +02:00
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType ;
import nodomain.freeyourgadget.gadgetbridge.model.GenericItem ;
2021-05-29 16:42:32 +02:00
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper ;
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils ;
import nodomain.freeyourgadget.gadgetbridge.util.GB ;
2020-04-10 00:48:46 +02:00
public class FossilHRInstallHandler implements InstallHandler {
2021-05-29 16:42:32 +02:00
private static final Logger LOG = LoggerFactory . getLogger ( FossilHRInstallHandler . class ) ;
2021-05-24 21:49:54 +02:00
private final Uri mUri ;
2020-04-10 00:48:46 +02:00
private final Context mContext ;
2021-05-24 21:49:54 +02:00
private FossilFileReader fossilFile ;
2020-04-10 00:48:46 +02:00
FossilHRInstallHandler ( Uri uri , Context context ) {
2021-05-24 21:49:54 +02:00
mUri = uri ;
2020-04-10 00:48:46 +02:00
mContext = context ;
try {
2021-05-24 21:49:54 +02:00
fossilFile = new FossilFileReader ( uri , mContext ) ;
} catch ( IOException ignored ) {
2020-04-10 00:48:46 +02:00
}
}
@Override
public void validateInstallation ( InstallActivity installActivity , GBDevice device ) {
if ( device . isBusy ( ) ) {
installActivity . setInfoText ( device . getBusyTask ( ) ) ;
installActivity . setInstallEnabled ( false ) ;
return ;
}
2021-05-24 21:49:54 +02:00
if ( device . getType ( ) ! = DeviceType . FOSSILQHYBRID | | ! device . isConnected ( ) | | ! fossilFile . isValid ( ) ) {
2022-07-06 23:09:36 +02:00
installActivity . setInfoText ( " Element cannot be installed 1, type: " + device . getType ( ) + " device: " + device + " is connected " + device . isConnected ( ) + " is valid file: " + fossilFile . isValid ( ) ) ;
2020-04-10 00:48:46 +02:00
installActivity . setInstallEnabled ( false ) ;
return ;
}
GenericItem installItem = new GenericItem ( ) ;
2021-05-29 16:42:32 +02:00
installItem . setName ( fossilFile . getName ( ) ) ;
installItem . setDetails ( fossilFile . getVersion ( ) ) ;
2022-07-29 15:53:48 +02:00
Bitmap preview = fossilFile . getPreview ( ) ;
if ( preview ! = null ) {
preview = Bitmap . createScaledBitmap ( preview , preview . getWidth ( ) * 3 , preview . getHeight ( ) * 3 , false ) ;
}
installItem . setPreview ( preview ) ;
2021-05-24 21:49:54 +02:00
if ( fossilFile . isFirmware ( ) ) {
installItem . setIcon ( R . drawable . ic_firmware ) ;
installActivity . setInfoText ( mContext . getString ( R . string . firmware_install_warning , " (unknown) " ) ) ;
} else if ( fossilFile . isApp ( ) ) {
installItem . setIcon ( R . drawable . ic_watchapp ) ;
installActivity . setInfoText ( mContext . getString ( R . string . app_install_info , installItem . getName ( ) , fossilFile . getVersion ( ) , " (unknown) " ) ) ;
} else if ( fossilFile . isWatchface ( ) ) {
installItem . setIcon ( R . drawable . ic_watchface ) ;
installActivity . setInfoText ( mContext . getString ( R . string . watchface_install_info , installItem . getName ( ) , fossilFile . getVersion ( ) , " (unknown) " ) ) ;
} else {
2022-07-06 23:09:36 +02:00
installActivity . setInfoText ( " Element cannot be installed 2 " ) ;
2021-05-24 21:49:54 +02:00
installActivity . setInstallEnabled ( false ) ;
return ;
}
2020-04-10 00:48:46 +02:00
installActivity . setInstallEnabled ( true ) ;
installActivity . setInstallItem ( installItem ) ;
}
@Override
public void onStartInstall ( GBDevice device ) {
2021-05-29 16:42:32 +02:00
DeviceCoordinator mCoordinator = DeviceHelper . getInstance ( ) . getCoordinator ( device ) ;
LocalBroadcastManager manager = LocalBroadcastManager . getInstance ( mContext ) ;
manager . sendBroadcast ( new Intent ( GB . ACTION_SET_PROGRESS_BAR ) . putExtra ( GB . PROGRESS_BAR_INDETERMINATE , true ) ) ;
if ( fossilFile . isFirmware ( ) ) {
return ;
}
2022-07-31 15:40:31 +02:00
saveAppInCache ( fossilFile , fossilFile . getBackground ( ) , fossilFile . getPreview ( ) , mCoordinator , mContext ) ;
2021-06-20 14:17:18 +02:00
// refresh list
manager . sendBroadcast ( new Intent ( AbstractAppManagerFragment . ACTION_REFRESH_APPLIST ) ) ;
}
2023-01-04 22:40:38 +01:00
public static boolean saveAppInCache ( FossilFileReader fossilFile , Bitmap backgroundImg , Bitmap previewImg , DeviceCoordinator mCoordinator , Context mContext ) {
2021-05-29 16:42:32 +02:00
GBDeviceApp app ;
File destDir ;
// write app file
try {
app = fossilFile . getGBDeviceApp ( ) ;
destDir = mCoordinator . getAppCacheDir ( ) ;
destDir . mkdirs ( ) ;
2021-06-20 14:17:18 +02:00
FileUtils . copyURItoFile ( mContext , fossilFile . getUri ( ) , new File ( destDir , app . getUUID ( ) . toString ( ) + mCoordinator . getAppFileExtension ( ) ) ) ;
2021-05-29 16:42:32 +02:00
} catch ( IOException e ) {
LOG . error ( " Saving app in cache failed: " + e . getMessage ( ) , e ) ;
2023-01-04 22:40:38 +01:00
return false ;
2021-05-29 16:42:32 +02:00
}
// write app metadata
File outputFile = new File ( destDir , app . getUUID ( ) . toString ( ) + " .json " ) ;
Writer writer ;
try {
writer = new BufferedWriter ( new FileWriter ( outputFile ) ) ;
} catch ( IOException e ) {
LOG . error ( " Failed to open output file: " + e . getMessage ( ) , e ) ;
2023-01-04 22:40:38 +01:00
return false ;
2021-05-29 16:42:32 +02:00
}
try {
LOG . info ( app . getJSON ( ) . toString ( ) ) ;
JSONObject appJSON = app . getJSON ( ) ;
JSONObject appKeysJSON = fossilFile . getAppKeysJSON ( ) ;
if ( appKeysJSON ! = null ) {
appJSON . put ( " appKeys " , appKeysJSON ) ;
}
writer . write ( appJSON . toString ( ) ) ;
writer . close ( ) ;
} catch ( IOException e ) {
LOG . error ( " Failed to write to output file: " + e . getMessage ( ) , e ) ;
2023-01-04 22:40:38 +01:00
return false ;
2021-05-29 16:42:32 +02:00
} catch ( JSONException e ) {
2023-01-04 22:40:38 +01:00
LOG . error ( " Failed to load or write appKeys JSON: " + e . getMessage ( ) , e ) ;
return false ;
2021-05-29 16:42:32 +02:00
}
2021-06-20 14:17:18 +02:00
// write watchface background image
if ( backgroundImg ! = null ) {
2022-07-29 15:53:48 +02:00
outputFile = new File ( destDir , app . getUUID ( ) . toString ( ) + " _bg.png " ) ;
2021-06-20 14:17:18 +02:00
try {
FileOutputStream fos = new FileOutputStream ( outputFile ) ;
backgroundImg . compress ( Bitmap . CompressFormat . PNG , 9 , fos ) ;
fos . close ( ) ;
} catch ( IOException e ) {
LOG . error ( " Failed to write to output file: " + e . getMessage ( ) , e ) ;
2023-01-04 22:40:38 +01:00
return false ;
2021-06-20 14:17:18 +02:00
}
}
2022-07-29 15:53:48 +02:00
// write watchface preview image
if ( previewImg ! = null ) {
outputFile = new File ( destDir , app . getUUID ( ) . toString ( ) + " _preview.png " ) ;
try {
FileOutputStream fos = new FileOutputStream ( outputFile ) ;
previewImg . compress ( Bitmap . CompressFormat . PNG , 9 , fos ) ;
fos . close ( ) ;
} catch ( IOException e ) {
LOG . error ( " Failed to write to output file: " + e . getMessage ( ) , e ) ;
2023-01-04 22:40:38 +01:00
return false ;
2022-07-29 15:53:48 +02:00
}
}
2023-01-04 22:40:38 +01:00
return true ;
2020-04-10 00:48:46 +02:00
}
@Override
public boolean isValid ( ) {
2021-05-24 21:49:54 +02:00
return fossilFile . isValid ( ) ;
2020-04-10 00:48:46 +02:00
}
}