-
Notifications
You must be signed in to change notification settings - Fork 75
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Replace Kotlin Android sample with Java Android sample (#529)
* replace Kotlin android sample with Java sample
- Loading branch information
Showing
4 changed files
with
329 additions
and
238 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
320 changes: 320 additions & 0 deletions
320
samples/Android/app/src/main/java/software/amazon/awssdk/iotsamples/MainActivity.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,320 @@ | ||
package software.amazon.awssdk.iotsamples; | ||
|
||
import android.os.Bundle; | ||
import android.view.View; | ||
import android.widget.AdapterView; | ||
import android.widget.ArrayAdapter; | ||
import android.widget.Spinner; | ||
import android.widget.TextView; | ||
|
||
import androidx.appcompat.app.AppCompatActivity; | ||
|
||
import java.io.IOException; | ||
import java.io.PrintStream; | ||
import java.io.InputStream; | ||
import java.io.FileOutputStream; | ||
import java.io.OutputStream; | ||
import java.lang.reflect.Method; | ||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.logging.Level; | ||
import java.util.logging.Logger; | ||
|
||
|
||
public class MainActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener { | ||
|
||
// Samples to load for the Android App | ||
private static final Map<String, String> SAMPLES = new HashMap<String, String>() {{ | ||
put("Select a Sample",""); // empty default | ||
put("Publish/Subscribe MQTT5 Sample", "mqtt5.pubsub.PubSub"); | ||
put("Publish/Subscribe MQTT3 Sample", "pubsub.PubSub"); | ||
put("Jobs Client Sample", "jobs.JobsSample"); | ||
put("Shadow Client Sample", "shadow.ShadowSample"); | ||
put("Cognito Client Sample", "cognitoconnect.CognitoConnect"); | ||
}}; | ||
|
||
private static final Logger logger = Logger.getLogger(MainActivity.class.getName()); | ||
private final StreamTee stdout; | ||
private final StreamTee stderr; | ||
private TextView console; | ||
private Spinner sampleSelect; | ||
|
||
private interface LogCallback { | ||
void log(String message); | ||
} | ||
|
||
private class StreamTee extends PrintStream { | ||
private final OutputStream source; | ||
private final LogCallback logCallback; | ||
|
||
public StreamTee(OutputStream source, LogCallback logCallback) { | ||
super(source, true); | ||
this.source = source; | ||
this.logCallback = logCallback; | ||
if (source == System.out) { | ||
System.setOut(this); | ||
} else if (source == System.err) { | ||
System.setErr(this); | ||
} | ||
} | ||
|
||
@Override | ||
public void write(byte[] buf, int off, int len) { | ||
try { | ||
source.write(buf, off, len); | ||
} catch (IOException e) { | ||
logger.log(Level.SEVERE, "An exception occurred in StreamTee", e); | ||
} | ||
logCallback.log(new String(buf, off, len)); | ||
} | ||
|
||
@Override | ||
public void write(byte[] b) { | ||
try { | ||
source.write(b); | ||
} catch (IOException e) { | ||
logger.log(Level.SEVERE, "An exception occurred in StreamTee", e); | ||
} | ||
logCallback.log(new String(b)); | ||
} | ||
} | ||
|
||
public MainActivity() { | ||
super(); | ||
stdout = new StreamTee(System.out, this::writeToConsole); | ||
stderr = new StreamTee(System.err, this::writeToConsole); | ||
} | ||
|
||
@Override | ||
protected void onCreate(Bundle savedInstanceState) { | ||
super.onCreate(savedInstanceState); | ||
setContentView(R.layout.activity_main); | ||
|
||
console = findViewById(R.id.console); | ||
console.setEnabled(false); | ||
|
||
sampleSelect = findViewById(R.id.sampleSelect); | ||
ArrayAdapter<String> samplesAdapter = new ArrayAdapter<>( | ||
this, R.layout.support_simple_spinner_dropdown_item, SAMPLES.keySet().toArray(new String[0]) | ||
); | ||
sampleSelect.setAdapter(samplesAdapter); | ||
sampleSelect.setOnItemSelectedListener(this); | ||
|
||
loadAssets(); | ||
} | ||
|
||
private void clearConsole() { | ||
runOnUiThread(() -> console.setText("")); | ||
} | ||
|
||
private void writeToConsole(String message) { | ||
runOnUiThread(() -> console.append(message)); | ||
} | ||
|
||
private void onSampleComplete() { | ||
runOnUiThread(() -> { | ||
writeToConsole("\nSample Complete\n"); | ||
sampleSelect.setSelection(0); | ||
sampleSelect.setEnabled(true); | ||
}); | ||
} | ||
|
||
private String assetContents(String assetName) throws IOException { | ||
try (InputStream res = getResources().getAssets().open(assetName)) { | ||
byte[] bytes = new byte[res.available()]; | ||
res.read(bytes); | ||
return new String(bytes).trim(); | ||
} catch (IOException e) { | ||
throw new IOException("Error reading asset file: " + assetName, e); | ||
} | ||
} | ||
|
||
Map<String, String> resourceMap = new HashMap<>(); | ||
|
||
// Load files from assets folder for use into resourceMap | ||
private void loadAssets(){ | ||
|
||
writeToConsole("Loading Asset Files:\n"); | ||
// Sample asset files in the assets folder | ||
List<String> resourceNames = new ArrayList<>(); | ||
resourceNames.add("endpoint.txt"); | ||
resourceNames.add("certificate.pem"); | ||
resourceNames.add("privatekey.pem"); | ||
resourceNames.add("cognitoIdentity.txt"); | ||
resourceNames.add("signingRegion.txt"); | ||
resourceNames.add("port.txt"); | ||
resourceNames.add("clientId.txt"); | ||
resourceNames.add("topic.txt"); | ||
resourceNames.add("message.txt"); | ||
resourceNames.add("thingName.txt"); | ||
resourceNames.add("rootca.pem"); | ||
|
||
// Copy to cache and store file locations for file assets and contents for .txt assets | ||
for (String resourceName : resourceNames) { | ||
try { | ||
try (InputStream res = getResources().getAssets().open(resourceName)) { | ||
// .txt files will store contents of the file | ||
if(resourceName.endsWith(".txt")){ | ||
byte[] bytes = new byte[res.available()]; | ||
res.read(bytes); | ||
String contents = new String(bytes).trim(); | ||
resourceMap.put(resourceName, contents); | ||
writeToConsole("'" + resourceName + "' file found and contents copied\n"); | ||
} else { | ||
// non .txt file types will copy to cache and store accessible file location | ||
String cachedName = getExternalCacheDir() + "/" + resourceName; | ||
try (OutputStream cachedRes = new FileOutputStream(cachedName)) { | ||
byte[] buffer = new byte[1024]; | ||
int length; | ||
while ((length = res.read(buffer)) != -1) { | ||
cachedRes.write(buffer, 0, length); | ||
} | ||
} | ||
resourceMap.put(resourceName, cachedName); | ||
writeToConsole("'" + resourceName + "' file found and cached\n"); | ||
} | ||
} | ||
} catch (IOException e) { | ||
writeToConsole("'" + resourceName + "' file not found\n"); | ||
} | ||
} | ||
} | ||
|
||
// Set a required argument from loaded assets | ||
private boolean argSetRequired(String argName, String fileName, List<String> args){ | ||
if(resourceMap.containsKey(fileName)){ | ||
args.addAll(List.of(argName, resourceMap.get(fileName))); | ||
return true; | ||
} | ||
writeToConsole("Required argument '" + argName + "' needs to be set. '" + fileName + "' File missing from assets folder\n"); | ||
return false; | ||
} | ||
|
||
// Check for optional argument and set if it's available | ||
private void argSetOptional(String argName, String fileName, List<String>args){ | ||
if(resourceMap.containsKey(fileName)){ | ||
args.addAll(List.of(argName, resourceMap.get(fileName))); | ||
} | ||
} | ||
|
||
// Retreive sample specific arguments needed from loaded asset files | ||
private String[] sampleArgs(String sampleClassName){ | ||
List<String> args = new ArrayList<>(); | ||
|
||
// Every sample requires the endpoint argument | ||
if (!argSetRequired("--endpoint", "endpoint.txt", args)){ | ||
return null; | ||
} | ||
|
||
// Shared optional arguments | ||
argSetOptional("--verbosity", "verbosity.txt", args); | ||
argSetOptional("--ca_file", "rootca.pem", args); | ||
argSetOptional("--port", "port.txt", args); | ||
argSetOptional("--client_id", "clientId.txt", args); | ||
|
||
// Missing required arguments will return null | ||
switch(sampleClassName){ | ||
case "mqtt5.pubsub.PubSub": | ||
case "pubsub.PubSub": | ||
if (!argSetRequired("--cert", "certificate.pem", args) || | ||
!argSetRequired("--key", "privatekey.pem", args)) { | ||
return null; | ||
} | ||
argSetOptional("--topic", "topic.txt", args); | ||
argSetOptional("--message", "message.txt", args); | ||
break; | ||
|
||
case "jobs.JobsSample": | ||
case "shadow.ShadowSample": | ||
if (!argSetRequired("--cert", "certificate.pem", args) || | ||
!argSetRequired("--key", "privatekey.pem", args) || | ||
!argSetRequired("--thing_name", "thingName.txt", args)) { | ||
return null; | ||
} | ||
break; | ||
|
||
case "cognitoconnect.CognitoConnect": | ||
if (!argSetRequired("--cognito_identity", "cognitoIdentity.txt", args) || | ||
!argSetRequired("--signing_region", "signingRegion.txt", args)) { | ||
return null; | ||
} | ||
break; | ||
} | ||
|
||
return args.toArray(new String[0]); | ||
} | ||
|
||
public class SampleRunnable implements Runnable { | ||
private final String[] args; | ||
private final Method sampleMain; | ||
|
||
public SampleRunnable(String[] args, Method sampleMain){ | ||
this.args = args; | ||
this.sampleMain = sampleMain; | ||
} | ||
|
||
@Override | ||
public void run(){ | ||
try { | ||
sampleMain.invoke(null, (Object) args); | ||
} catch (Exception e){ | ||
writeToConsole("Exception occurred in run()" + e.toString() + "\n"); | ||
} | ||
onSampleComplete(); | ||
} | ||
} | ||
|
||
private void runSample(String sampleName, String sampleClassName){ | ||
ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); | ||
Class<?> sampleClass = null; | ||
|
||
try { | ||
sampleClass = classLoader.loadClass(sampleClassName); | ||
} catch (ClassNotFoundException e){ | ||
writeToConsole("Cound not find sample '" + sampleClassName + "'\n"); | ||
return; | ||
} | ||
|
||
if(sampleClass != null){ | ||
Method main = null; | ||
try { | ||
main = sampleClass.getMethod("main", String[].class); | ||
if (main != null){ | ||
sampleSelect.setEnabled(false); | ||
writeToConsole("Running '" + sampleName + "''\n\n"); | ||
String[] args = sampleArgs(sampleClassName); | ||
if (args == null){ | ||
writeToConsole("Missing required arguments/files\n"); | ||
onSampleComplete(); | ||
return; | ||
} | ||
new Thread(new SampleRunnable(sampleArgs(sampleClassName), main), "sample_runner").start(); | ||
} | ||
} catch (Exception e) { | ||
writeToConsole("Exception encountered: " + e.toString()); | ||
onSampleComplete(); | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) { | ||
String sampleName = parent.getItemAtPosition(pos).toString(); | ||
if (sampleName != "Select a Sample") { | ||
clearConsole(); | ||
String sampleClassName = SAMPLES.get(sampleName); | ||
if (sampleClassName != null) { | ||
runSample(sampleName, sampleClassName); | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
public void onNothingSelected(AdapterView<?> parent) { | ||
clearConsole(); | ||
writeToConsole("Please select a sample above"); | ||
} | ||
} |
Oops, something went wrong.