2016-02-28 22:25:21 +01:00
package nodomain.freeyourgadget.gadgetbridge.activities ;
2016-03-13 08:31:50 +01:00
import android.content.Intent ;
2016-02-28 22:25:21 +01:00
import android.net.Uri ;
import android.os.Bundle ;
2016-03-03 13:05:51 +01:00
import android.support.v4.app.NavUtils ;
2016-04-09 05:41:31 +02:00
import android.support.v7.app.AppCompatActivity ;
2016-02-28 22:25:21 +01:00
import android.util.Log ;
2016-03-03 13:05:51 +01:00
import android.view.MenuItem ;
2016-03-18 17:50:24 +01:00
import android.webkit.ConsoleMessage ;
2016-02-28 22:25:21 +01:00
import android.webkit.JavascriptInterface ;
2016-03-18 17:50:24 +01:00
import android.webkit.WebChromeClient ;
2016-02-28 22:25:21 +01:00
import android.webkit.WebSettings ;
import android.webkit.WebView ;
2016-03-08 21:44:12 +01:00
import android.webkit.WebViewClient ;
2016-02-28 22:25:21 +01:00
import android.widget.Toast ;
import org.json.JSONException ;
import org.json.JSONObject ;
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
import java.io.File ;
import java.io.IOException ;
import java.util.Iterator ;
import java.util.UUID ;
2016-03-03 14:23:17 +01:00
import nodomain.freeyourgadget.gadgetbridge.GBApplication ;
2016-02-28 22:25:21 +01:00
import nodomain.freeyourgadget.gadgetbridge.R ;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice ;
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils ;
import nodomain.freeyourgadget.gadgetbridge.util.GB ;
2016-03-03 11:52:30 +01:00
import nodomain.freeyourgadget.gadgetbridge.util.PebbleUtils ;
2016-02-28 22:25:21 +01:00
2016-04-09 05:41:31 +02:00
public class ExternalPebbleJSActivity extends AppCompatActivity {
2016-02-28 22:25:21 +01:00
private static final Logger LOG = LoggerFactory . getLogger ( ExternalPebbleJSActivity . class ) ;
private UUID appUuid ;
2016-03-03 11:52:30 +01:00
private GBDevice mGBDevice = null ;
2016-02-28 22:25:21 +01:00
@Override
protected void onCreate ( Bundle savedInstanceState ) {
super . onCreate ( savedInstanceState ) ;
2016-03-03 11:52:30 +01:00
Bundle extras = getIntent ( ) . getExtras ( ) ;
if ( extras ! = null ) {
mGBDevice = extras . getParcelable ( GBDevice . EXTRA_DEVICE ) ;
} else {
throw new IllegalArgumentException ( " Must provide a device when invoking this activity " ) ;
}
2016-02-28 22:25:21 +01:00
String queryString = " " ;
2016-03-03 13:05:51 +01:00
Uri uri = getIntent ( ) . getData ( ) ;
2016-02-28 22:25:21 +01:00
if ( uri ! = null ) {
//getting back with configuration data
appUuid = UUID . fromString ( uri . getHost ( ) ) ;
queryString = uri . getEncodedQuery ( ) ;
} else {
appUuid = ( UUID ) getIntent ( ) . getSerializableExtra ( " app_uuid " ) ;
}
setContentView ( R . layout . activity_external_pebble_js ) ;
WebView myWebView = ( WebView ) findViewById ( R . id . configureWebview ) ;
myWebView . clearCache ( true ) ;
2016-03-08 21:44:12 +01:00
myWebView . setWebViewClient ( new GBWebClient ( ) ) ;
2016-03-18 17:50:24 +01:00
myWebView . setWebChromeClient ( new GBChromeClient ( ) ) ;
2016-02-28 22:25:21 +01:00
WebSettings webSettings = myWebView . getSettings ( ) ;
webSettings . setJavaScriptEnabled ( true ) ;
//needed to access the DOM
webSettings . setDomStorageEnabled ( true ) ;
JSInterface gbJSInterface = new JSInterface ( ) ;
myWebView . addJavascriptInterface ( gbJSInterface , " GBjs " ) ;
2016-03-03 11:54:07 +01:00
myWebView . loadUrl ( " file:///android_asset/app_config/configure.html? " + queryString ) ;
2016-02-28 22:25:21 +01:00
}
private JSONObject getAppConfigurationKeys ( ) {
try {
File destDir = new File ( FileUtils . getExternalFilesDir ( ) + " /pbw-cache " ) ;
File configurationFile = new File ( destDir , appUuid . toString ( ) + " .json " ) ;
2016-03-03 11:54:07 +01:00
if ( configurationFile . exists ( ) ) {
2016-02-28 22:25:21 +01:00
String jsonstring = FileUtils . getStringFromFile ( configurationFile ) ;
JSONObject json = new JSONObject ( jsonstring ) ;
return json . getJSONObject ( " appKeys " ) ;
}
2016-03-03 13:05:51 +01:00
} catch ( IOException | JSONException e ) {
2016-02-28 22:25:21 +01:00
e . printStackTrace ( ) ;
}
return null ;
}
2016-03-18 17:50:24 +01:00
private class GBChromeClient extends WebChromeClient {
@Override
public boolean onConsoleMessage ( ConsoleMessage consoleMessage ) {
2016-03-21 21:19:32 +01:00
if ( ConsoleMessage . MessageLevel . ERROR . equals ( consoleMessage . messageLevel ( ) ) ) {
GB . toast ( consoleMessage . message ( ) , Toast . LENGTH_LONG , GB . ERROR ) ;
//TODO: show error page
}
2016-03-18 17:50:24 +01:00
return super . onConsoleMessage ( consoleMessage ) ;
}
2016-03-21 21:19:32 +01:00
2016-03-18 17:50:24 +01:00
}
2016-03-20 15:00:05 +01:00
2016-03-08 21:44:12 +01:00
private class GBWebClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading ( WebView view , String url ) {
2016-03-13 08:31:50 +01:00
if ( url . startsWith ( " http:// " ) | | url . startsWith ( " https:// " ) ) {
Intent i = new Intent ( Intent . ACTION_VIEW ,
Uri . parse ( url ) ) ;
startActivity ( i ) ;
} else {
url = url . replaceFirst ( " ^pebblejs://close# " , " file:///android_asset/app_config/configure.html?config=true&json= " ) ;
view . loadUrl ( url ) ;
}
2016-03-08 21:44:12 +01:00
return true ;
}
}
2016-02-28 22:25:21 +01:00
private class JSInterface {
2016-03-03 11:54:07 +01:00
public JSInterface ( ) {
2016-02-28 22:25:21 +01:00
}
@JavascriptInterface
public void gbLog ( String msg ) {
Log . d ( " WEBVIEW " , msg ) ;
}
@JavascriptInterface
public void sendAppMessage ( String msg ) {
2016-03-03 14:23:17 +01:00
LOG . debug ( " from WEBVIEW: " , msg ) ;
2016-02-28 22:25:21 +01:00
JSONObject knownKeys = getAppConfigurationKeys ( ) ;
2016-03-03 11:54:07 +01:00
try {
2016-02-28 22:25:21 +01:00
JSONObject in = new JSONObject ( msg ) ;
2016-03-03 14:23:17 +01:00
JSONObject out = new JSONObject ( ) ;
2016-02-28 22:25:21 +01:00
String cur_key ;
2016-03-03 11:54:07 +01:00
for ( Iterator < String > key = in . keys ( ) ; key . hasNext ( ) ; ) {
2016-02-28 22:25:21 +01:00
cur_key = key . next ( ) ;
int pebbleAppIndex = knownKeys . optInt ( cur_key ) ;
if ( pebbleAppIndex ! = 0 ) {
2016-03-03 16:02:30 +01:00
Object obj = in . get ( cur_key ) ;
if ( obj instanceof Boolean ) {
obj = ( ( Boolean ) obj ) ? " true " : " false " ;
}
out . put ( String . valueOf ( pebbleAppIndex ) , obj ) ;
2016-02-28 22:25:21 +01:00
} else {
2016-03-03 11:54:07 +01:00
GB . toast ( " Discarded key " + cur_key + " , not found in the local configuration. " , Toast . LENGTH_SHORT , GB . WARN ) ;
2016-02-28 22:25:21 +01:00
}
}
2016-03-03 14:23:17 +01:00
LOG . info ( out . toString ( ) ) ;
GBApplication . deviceService ( ) . onAppConfiguration ( appUuid , out . toString ( ) ) ;
2016-02-28 22:25:21 +01:00
} catch ( JSONException e ) {
e . printStackTrace ( ) ;
}
}
@JavascriptInterface
public String getActiveWatchInfo ( ) {
JSONObject wi = new JSONObject ( ) ;
try {
2016-03-13 08:31:50 +01:00
wi . put ( " firmware " , mGBDevice . getFirmwareVersion ( ) ) ;
2016-03-03 11:52:30 +01:00
wi . put ( " platform " , PebbleUtils . getPlatformName ( mGBDevice . getHardwareVersion ( ) ) ) ;
2016-03-04 17:44:42 +01:00
wi . put ( " model " , PebbleUtils . getModel ( mGBDevice . getHardwareVersion ( ) ) ) ;
//TODO: use real info
2016-03-13 08:31:50 +01:00
wi . put ( " language " , " en " ) ;
2016-03-03 11:54:07 +01:00
} catch ( JSONException e ) {
2016-02-28 22:25:21 +01:00
e . printStackTrace ( ) ;
}
//Json not supported apparently, we need to cast back and forth
return wi . toString ( ) ;
}
@JavascriptInterface
public String getAppConfigurationFile ( ) {
try {
File destDir = new File ( FileUtils . getExternalFilesDir ( ) + " /pbw-cache " ) ;
File configurationFile = new File ( destDir , appUuid . toString ( ) + " _config.js " ) ;
2016-03-03 11:54:07 +01:00
if ( configurationFile . exists ( ) ) {
return " file:/// " + configurationFile . getAbsolutePath ( ) ;
2016-02-28 22:25:21 +01:00
}
} catch ( IOException e ) {
e . printStackTrace ( ) ;
}
return null ;
}
@JavascriptInterface
public String getAppUUID ( ) {
return appUuid . toString ( ) ;
}
2016-03-13 08:31:50 +01:00
2016-03-04 17:44:42 +01:00
@JavascriptInterface
public String getWatchToken ( ) {
//specification says: A string that is is guaranteed to be identical for each Pebble device for the same app across different mobile devices. The token is unique to your app and cannot be used to track Pebble devices across applications. see https://developer.pebble.com/docs/js/Pebble/
2016-03-13 08:31:50 +01:00
return " gb " + appUuid . toString ( ) ;
2016-03-04 17:44:42 +01:00
}
2016-02-28 22:25:21 +01:00
}
2016-03-03 13:05:51 +01:00
@Override
public boolean onOptionsItemSelected ( MenuItem item ) {
switch ( item . getItemId ( ) ) {
case android . R . id . home :
NavUtils . navigateUpFromSameTask ( this ) ;
return true ;
}
return super . onOptionsItemSelected ( item ) ;
}
2016-02-28 22:25:21 +01:00
}