I have the following code to use to execute a root command:
public static String sudo(final String cmd, Context ctx) {
String output = null; //init string output
if (RootTools.isRootAvailable()) {
if (RootTools.isAccessGiven()) {
try {
CommandCapture command = new CommandCapture(0, cmd) {
#Override
public void output(int id, String line) {
Log.d("com.vwade79.aokpdelta.Functions.sudo", "cmd:"+cmd+"\noutput:"+line);
if (line.equals("")) {
return;
}
else {
output = line; //ERROR
}
}
};
RootTools.getShell(true).add(command).waitForFinish();
} catch (Exception e) {
Toast.makeText(ctx, "There was an error executing root command : "+cmd, Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}
else {
Toast.makeText(ctx, "Root permission isn't given!", Toast.LENGTH_LONG).show();
Intent intent = new Intent(ctx, MainActivity.class);
ctx.startActivity(intent);
}
}
else {
Toast.makeText(ctx, "You're not rooted! Come back when you are!", Toast.LENGTH_LONG).show();
Intent intent = new Intent(ctx, MainActivity.class);
ctx.startActivity(intent);
}
return output;
}
I am getting an error:
variable "output" is accessed from within inner class. Needs to be declared final.
I don't know how to assign the output from the "inner class".
The error message says it all: you can only access final variables from within an inner class.
A quick solution would be to define:
final String output[] = new String[1]; //init string output
and in the inner class:
output[0] = line; // No ERROR :-)
and then:
return output[0];
This is, because the array itself is final, but the contents of the array can still be changed (a little strange definition of final in Java, if you ask me; final does not mean immutable).
Related
I have a DoFn that is supposed to split input into two separate PCollections. The pipeline builds and runs up until it is time to output in the DoFn, and then I get the following exception:
"java.lang.IllegalArgumentException: Unknown output tag Tag<edu.mayo.mcc.cdh.pipeline.PubsubToAvro$PubsubMessageToArchiveDoFn$2.<init>:219#2587af97b4865538>
at org.apache.beam.vendor.guava.v26_0_jre.com.google.common.base.Preconditions.checkArgument(Preconditions.java:216)...
If I declare the TupleTags I'm using in the ParDo, I get that error, but if I declare them outside of the ParDo I get a syntax error saying the OutputReceiver can't find the tags. Below is the apply and the ParDo/DoFn:
PCollectionTuple results = (messages.apply("Map to Archive", ParDo.of(new PubsubMessageToArchiveDoFn()).withOutputTags(noTag, TupleTagList.of(medaPcollection))));
PCollection<AvroPubsubMessageRecord> medaPcollectionTransformed = results.get(medaPcollection);
PCollection<AvroPubsubMessageRecord> noTagPcollectionTransformed = results.get(noTag);
static class PubsubMessageToArchiveDoFn extends DoFn<PubsubMessage, AvroPubsubMessageRecord> {
final TupleTag<AvroPubsubMessageRecord> medaPcollection = new TupleTag<AvroPubsubMessageRecord>(){};
final TupleTag<AvroPubsubMessageRecord> noTag = new TupleTag<AvroPubsubMessageRecord>(){};
#ProcessElement
public void processElement(ProcessContext context, MultiOutputReceiver out) {
String appCode;
PubsubMessage message = context.element();
String msgStr = new String(message.getPayload(), StandardCharsets.UTF_8);
try {
JSONObject jsonObject = new JSONObject(msgStr);
LOGGER.info("json: {}", jsonObject);
appCode = jsonObject.getString("app_code");
LOGGER.info(appCode);
if(appCode == "MEDA"){
LOGGER.info("Made it to MEDA tag");
out.get(medaPcollection).output(new AvroPubsubMessageRecord(
message.getPayload(), message.getAttributeMap(), context.timestamp().getMillis()));
} else {
LOGGER.info("Made it to default tag");
out.get(noTag).output(new AvroPubsubMessageRecord(
message.getPayload(), message.getAttributeMap(), context.timestamp().getMillis()));
}
} catch (Exception e) {
LOGGER.info("Error Processing Message: {}\n{}", msgStr, e);
}
}
}
Can you try without MultiOutputReceiver out parameter in the processElement method ?
Outputs are then returned with context.output with passing element and corresponding TupleTag.
Your example only with context :
static class PubsubMessageToArchiveDoFn extends DoFn<PubsubMessage, AvroPubsubMessageRecord> {
final TupleTag<AvroPubsubMessageRecord> medaPcollection = new TupleTag<AvroPubsubMessageRecord>(){};
final TupleTag<AvroPubsubMessageRecord> noTag = new TupleTag<AvroPubsubMessageRecord>(){};
#ProcessElement
public void processElement(ProcessContext context) {
String appCode;
PubsubMessage message = context.element();
String msgStr = new String(message.getPayload(), StandardCharsets.UTF_8);
try {
JSONObject jsonObject = new JSONObject(msgStr);
LOGGER.info("json: {}", jsonObject);
appCode = jsonObject.getString("app_code");
LOGGER.info(appCode);
if(appCode == "MEDA"){
LOGGER.info("Made it to MEDA tag");
context.output(medaPcollection, new AvroPubsubMessageRecord(
message.getPayload(), message.getAttributeMap(), context.timestamp().getMillis()));
} else {
LOGGER.info("Made it to default tag");
context.output(noTag, new AvroPubsubMessageRecord(
message.getPayload(), message.getAttributeMap(), context.timestamp().getMillis()));
}
} catch (Exception e) {
LOGGER.info("Error Processing Message: {}\n{}", msgStr, e);
}
}
I also show you an example that works for me :
public class WordCountFn extends DoFn<String, Integer> {
private final TupleTag<Integer> outputTag = new TupleTag<Integer>() {};
private final TupleTag<Failure> failuresTag = new TupleTag<Failure>() {};
#ProcessElement
public void processElement(ProcessContext ctx) {
try {
// Could throw ArithmeticException.
final String word = ctx.element();
ctx.output(1 / word.length());
} catch (Throwable throwable) {
final Failure failure = Failure.from("step", ctx.element(), throwable);
ctx.output(failuresTag, failure);
}
}
public TupleTag<Integer> getOutputTag() {
return outputTag;
}
public TupleTag<Failure> getFailuresTag() {
return failuresTag;
}
}
In my first output (good case), no need to pass the TupleTag ctx.output(1 / word.length());
For my second output (failure case), I pass the Failure tag with the corresponding element.
I was able to get around this by making my ParDo an anonymous function instead of a class. I put the whole function inline and had no problem finding the output tags after I did that. Thanks for the suggestions!
I am making a qr code scanner app and I can't complete two things. The first one is to pass information about Vcard to a new Activity. Here is the code I wrote:
#Override
public void handleResult(Result rawResult) {
processRawResult(rawResult.getText());
}
private void processRawResult(String text){
if (text.startsWith("BEGIN:")) {
String[] tokens = text.split("\n");
QRVcardModel qrVcardModel = new QRVcardModel();
for (int i = 0; i < tokens.length; i++) {
if (tokens[i].startsWith("BEGIN:")) {
qrVcardModel.setType(tokens[i].substring("BEGIN:".length()));
} else if (tokens[i].startsWith("N:")) {
qrVcardModel.setName(tokens[i].substring("N:".length()));
} else if (tokens[i].startsWith("ORG:")) {
qrVcardModel.setOrg(tokens[i].substring("ORG:".length()));
} else if (tokens[i].startsWith("TEL:")) {
qrVcardModel.setTel(tokens[i].substring("TEL:".length()));
} else if (tokens[i].startsWith("URl:")) {
qrVcardModel.setUrl(tokens[i].substring("URL:".length()));
} else if (tokens[i].startsWith("EMAIL:")) {
qrVcardModel.setEmail(tokens[i].substring("EMAIL:".length()));
} else if (tokens[i].startsWith("ADR:")) {
qrVcardModel.setAddress(tokens[i].substring("ADR:".length()));
} else if (tokens[i].startsWith("NOTE:")) {
qrVcardModel.setNote(tokens[i].substring("NOTE:".length()));
} else if (tokens[i].startsWith("SUMMARY:")) {
qrVcardModel.setSummary(tokens[i].substring("SUMMARY:".length()));
} else if (tokens[i].startsWith("DTSTART:")) {
qrVcardModel.setDtstart(tokens[i].substring("DTSTART:".length()));
} else if (tokens[i].startsWith("DTEND:")) {
qrVcardModel.setDtend(tokens[i].substring("DTEND:".length()));
}
}
Intent intentVcard = new Intent(MainActivity.this, VcardActivity.class);
startActivity(intentVcard);
}
The second problem I face is that I can't open Google Maps app when I scan the Geoqrcode. Here is the code:
else if (text.startsWith("geo:"))
{
QRGeoModel qrGeoModel = new QRGeoModel();
String delims = "[ , ?q= ]+";
String tokens[] = text.split(delims);
for (int i=0;i<tokens.length;i++)
{
if (tokens[i].startsWith(" geo:"))
{
qrGeoModel.setLat(tokens[i].substring("geo:".length()));
}
}
qrGeoModel.setLat(tokens[0].substring("geo:".length()));
qrGeoModel.setLng(tokens[1]);
qrGeoModel.setGeo_place(tokens[2]);
Uri gmmIntentUri = Uri.parse("qrGeoModel.getLat(),qrGeoModel.getLng()");
Intent mapIntent = new Intent(Intent.ACTION_VIEW, gmmIntentUri);
mapIntent.setPackage("com.google.android.apps.maps");
startActivity(mapIntent);
}
Do you know how can I do that two?
You can pass values in Intent like this :
intentVcard.putExtra("value_name" , value);
value can be String, int, boolean, long and more (you can check in your ide what you can pass).
On the recieving activity you can get the value like this :
getIntent.getStrinExtra("value_name");
Be sure to replace it by your value name, for String it is like this, however for boolean it will be :
getIntent.getBooleanExtra("value_name" , defualt_value);
About the Google Maps problem, look at this line
Uri gmmIntentUri = Uri.parse("qrGeoModel.getLat(),qrGeoModel.getLng()");
you don't need " there, that way you will pass it all as a string and not the actual value of qrGeoModel.getLat(), insted write this line like that :
Uri gmmIntentUri = Uri.parse(qrGeoModel.getLat() + "," + qrGeoModel.getLng());
I'm pretty new to Java, and currently build client program based on Android.
I have backend server written in Python that will produce result containing some List inside Array.
Here is result from python I should get:
[[id, shopName], [id, shopName], ...]
Example:
[[1, Jakarta], [2, Bali], ...]
Basically, I need to have String[] containing id, and String[] containing name, for spinner adapter.
String[] shopServId, shopServName;
List arrayListShopServId, arrayListShopServName;
// in onCreate()
arrayListShopServId = new ArrayList();
arrayListShopServName = new ArrayList();
and on XMLRPCCallback listener onResponse()
Object[] classObjs = (Object[]) result;
int length = classObjs.length;
shopServId = new String[classObjs.length];
shopServName = new String[classObjs.length];
if ( length > 0) {
arrayListShopServId.clear();
arrayListShopServName.clear();
for (int i=0; i<length; i++) {
#SuppressWarnings("unchecked")
Map<String,Object> classObj = (Map<String,Object>)classObjs[i];
arrayListShopServId.add(classObj.get("id"));
arrayListShopServName.add(classObj.get("name"));
// id and name here are object fields key to get by using XMLRPC
shopServId[i] = arrayListShopServId.get(i).toString();
shopServName[i] = arrayListShopServName.get(i).toString();
}
runOnUiThread(new Runnable() {
#Override
public void run() {
loadSpinnerSaleShop();
}
});
} else {
System.out.println("SaleShop not found!");
}
But it gives me an error
java.lang.ClassCastException: java.lang.Object[] cannot be cast to java.util.Map
How can I achieve that?
EDIT
For those who want to know, I use XMLRPC AsynTask.
Full part of the relevant code:
TaskId:
private void readSaleShop() {
readSaleShopTaskId = util.soe_salesman_shops(listener, database, uid, password, "sale.order",
employeeId);
}
The Listener:
XMLRPCCallback listener = new XMLRPCCallback() {
public void onResponse(long id, Object result) {
Looper.prepare();
if(id==readSaleShopTaskId) {
Object[] classObjs = (Object[]) result;
int length = classObjs.length;
shopServId = new String[classObjs.length];
shopServName = new String[classObjs.length];
if ( length > 0) {
arrayListShopServId.clear();
arrayListShopServName.clear();
for (int i=0; i<length; i++) {
#SuppressWarnings("unchecked")
Map<String,Object> classObj = (Map<String,Object>)classObjs[i];
arrayListShopServId.add(classObj.get("id"));
arrayListShopServName.add(classObj.get("name"));
shopServId[i] = arrayListShopServId.get(i).toString();
shopServName[i] = arrayListShopServName.get(i).toString();
}
runOnUiThread(new Runnable() {
#Override
public void run() {
loadSpinnerSaleShop();
}
});
} else {
System.out.println("SaleShop not found!");
}
} else if(id==updateSaleOrderTaskId) {
final Boolean updateResult =(Boolean)result;
if(updateResult)
{
Log.v("SO UPDATE", "successfully");
util.MessageDialog(SOFormActivity.this,
"Update SO succeed.");
}
else{
util.MessageDialog(SOFormActivity.this,
"Update SO failed. Server return was false");
}
} else if (id == createSOTaskId) {
String createResult = result.toString();
if(createResult != null)
{
Log.v("SO CREATE", "successfully");
util.MessageDialog(SOFormActivity.this,
"Create SO succeed. ID = " + createResult);
}
else
{
util.MessageDialog(SOFormActivity.this,
"Create SO failed. Server return was false");
}
}
Looper.loop();
}
public void onError(long id, XMLRPCException error) {
Looper.prepare();
Log.e("SOForm", error.getMessage());
util.MessageDialog(SOFormActivity.this, error.getMessage());
Looper.loop();
}
public void onServerError(long id, XMLRPCServerException error) {
Looper.prepare();
Log.e("SOForm", error.getMessage());
util.MessageDialog(SOFormActivity.this, error.getMessage());
Looper.loop();
}
};
method I use from UtilAsync class:
public long soe_salesman_shops(XMLRPCCallback listener, String db, String uid, String password,
String object, String employeeId) {
long id = client.callAsync(listener, "execute", db, Integer.parseInt(uid), password, object,
"soe_salesman_shops", Integer.parseInt(employeeId));
return id;
}
classObjs[i] is a an object array. What you can do is cast it to an Array and then get the required data:
Object[] classObj = (Object[])classObjs[i];
arrayListShopServId.add(classObj[0]);
arrayListShopServName.add(classObj[1]);
Your result is a Object[][], so you can do
classObj.put(classObjs[i][0], classObjs[i][1]);
But you can directly do
arrayListShopServId.add(classObjs[i][0]);
arrayListShopServName.add(classObjs[i][1]);
This is a normal behavior.
You have :
Object[] classObjs = (Object[]) result;
Map<String,Object> classObj = (Map<String,Object>)classObjs[i];
You're trying to cast an Object[] element (classObjs[i]) to a different type (Map).
You have to construct the element of the classObj Map in a proper way.
I've ended up changing my python code so it will produce result List of Python Dictionary like this
[{'id':id, 'name':name}, {'id':id, 'name':name}, ...}]
So my code is working now.
But still confuse how to get certain element from List inside List.
So, if someone have working solution, I'll mark that as an answer.
So far I've been making applications with set as Ringtone feature by creating 1 activity for 1 file. It was bad because with apps with more than 20 ringtones I would've needed 20 activities which would affect app size and performance. Then I found that there is a way to do that with only 1 activity and layout, passing data with Intents. Now I have pretty good idea how that works except one thing that bothers me. That is how do I define strings.
I need 1 string for name and 1 for file path
My code:
Boolean success = false;
rsound = new File(rpath, "Slow tone.mp3");rpath.mkdirs(); //Copied file name
if (!rsound.exists()) {
try {
InputStream in = getResources().openRawResource(R.raw.s8slowtone); //path for file
FileOutputStream out = new FileOutputStream(rsound.getPath());
byte[] buff = new byte[1024];
int read = 0;
try {
while ((read = in.read(buff)) > 0) {
out.write(buff, 0, read);
}
} finally {
in.close();
out.close();
}
} catch (Exception e) {
success = false;
}
} else {
success = true;
setRingtone();
}
if (!success) {
setRingtone();
}
}
private void setRingtone() {
ContentValues values = new ContentValues();
values.put(MediaStore.MediaColumns.DATA, rsound.getAbsolutePath());
values.put(MediaStore.MediaColumns.TITLE, "Slow tone"); //Ringtone name
values.put(MediaStore.MediaColumns.MIME_TYPE, "audio/*");
values.put(MediaStore.Audio.Media.ARTIST, " ");
values.put(MediaStore.Audio.Media.IS_RINGTONE, true);
values.put(MediaStore.Audio.Media.IS_NOTIFICATION, false);
values.put(MediaStore.Audio.Media.IS_ALARM, false);
values.put(MediaStore.Audio.Media.IS_MUSIC, true);
Uri uri = MediaStore.Audio.Media.getContentUriForPath(rsound.getAbsolutePath());
getContentResolver().delete(uri, MediaStore.MediaColumns.DATA + "=\"" + rsound.getAbsolutePath() + "\"",
null);
Uri newUri = getContentResolver().insert(uri, values);
RingtoneManager.setActualDefaultRingtoneUri(
S15.this, RingtoneManager.TYPE_RINGTONE,
newUri);
Toast.makeText(getApplicationContext(), "Ringtone set successfully",
Toast.LENGTH_SHORT).show();
So How do I do this? How do I define string for each file and how to pass them?
Since question is unclear for some members I will make it simpler
I don't have idea how should I write strings so when I start RingtoneManager Activity using Intent, I pass data from strings.
So How should I write my code to pass this
File name "Slow tone.mp3"
File path: R.raw.s8slowtone)
Ringtone name "Slow tone"
To call your activity, just place this function anywhere, and call it with your desired parameters. It will build an intent and fill in the parameters:
public static void runRingToneActivity(Context context, String ringToneName, String ringTonePath, String ringToneFilename) {
Intent intent=new Intent(context, RingToneActivity.class);
intent.putExtra("NAME", ringToneName);
intent.putExtra("PATH", ringTonePath);
intent.putExtra("FILE", ringToneFileName);
((Activity)context).startActivity(intent);
}
Inside your RingToneActivity's onCreate, you just retrieve the parameters you just passed:
#Override
protected void onCreate(Bundle savedInstanceState) {
.
.
Intent intent=this.getIntent();
String ringtoneName=intent.getStringExtra("NAME");
String ringtonePath=intent.getStringExtra("PATH");
String ringtoneFile=intent.getStringExtra("FILE");
// you have them, now use them!
}
NOTES:
Substitute "RingToneActivity.class" in the function for the name of your activity, if it is different.
Intent f27=new Intent(context, RMpro.class);
if (f27 != null){
f27.putExtra("FileName", "Horn!"); //Copied file name
int res = R.raw.s28horn; // Path to File in App ressources
f27.putExtra("FilePath", res); //Passing path with intent
f27.putExtra("RingName", "Horn.mp3"); // Ring name
((Activity)context).startActivity(f27);
}
And then in Ringtone Manager, in my case RMpro
final int FPATH=i.getExtras().getInt("FilePath");
final String RNAME = getIntent().getStringExtra("RingName").trim();
final String FNAME = getIntent().getStringExtra("FileName").trim();
And then just:
rsound = new File(rpath, FNAME);rpath.mkdirs();
InputStream in = getResources().openRawResource(FPATH);
values.put(MediaStore.MediaColumns.TITLE, RNAME);
You can pass entire objects via intent. You just need to implement Serializable interface for the class you want to pass. Example:
public class Ringtone implements Serializable
{
public String name;
public String path; //can be integer
public String file;
}
send via intent:
Ringtone ringtoneObj = new Ringtone();
intent.putExtra("test",ringtoneObj);
retrieve via intent:
Ringtone ringtoneFromIntent = (Ringtone) intent.getSerializableExtra("test");
is there any other way to import another Java class from the same package in android?
I'm trying to import store.class to SMSreceiver.class
in SMSreceiver.class, i type in this code, store storingKey = new store();
but still cannot call the methods in store.class
this will be my store.class coding.
public class store extends Activity{
public store(){
}
public void saveToFile(String filename, String sms) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException{
OutputStreamWriter out = new OutputStreamWriter(openFileOutput(filename, Context.MODE_APPEND));
out.write(sms);
out.close();
}
is there any problem with my coding?
any help?
Rob, this is my another class
public class storePubKey extends BroadcastReceiver
{
Activity ac = new Activity();
store sk = new store();
public void onReceive(Context context, Intent intent)
{
//---get the SMS message passed in---
Bundle bundle = intent.getExtras();
SmsMessage[] msgs = null;
String str = "";
if (bundle != null)
{
try{
//---retrieve the SMS message received---
Object[] pdus = (Object[]) bundle.get("pdus");
msgs = new SmsMessage[pdus.length];
for (int i=0; i<msgs.length; i++){
msgs[i] = SmsMessage.createFromPdu((byte[])pdus[i]);
str = msgs[i].getMessageBody().toString();
Toast.makeText(context, "f", Toast.LENGTH_SHORT).show();
sk.saveToFile("public.key", str);
Toast.makeText(context,("public.keyasd"), Toast.LENGTH_SHORT).show();
}
}catch(Exception e){}
}
//---display the new SMS message---
try {
//Toast.makeText(context,str, Toast.LENGTH_SHORT).show();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
EDIT: Try this
To call a non-static method in another class, you need a reference to that class.
store storeRef = new store(); // create new instance and set reference
storeRef.saveToFile(); // call the method
If you already have a reference to that class, you don't need to create it. A reference can be passed in a method call:
public void calledMethod(store storeRef) {
storeRef.saveToFile();
UPDATE
Change
storeKey sk = new storeKey();
to
store sk = new store();
Since store is your original class name, not storeKey.
You also may need to declare that withing the method you are trying to use it in.