ScrollTo and ScrollToExact equivalent for webView in appium for android - android

I am automating android app using appium (java).For scrolling on native components, I use scrollTo() and scrollToExact() methods.But in case of webView inside the app ; these methods are not working.
UPDATE:
I have tried these two methods also:
public static void scrollNavigation(AppiumDriver<MobileElement> wd, String widID, String target, String direction)
{
JavascriptExecutor js = (JavascriptExecutor) wd;
HashMap<String, String> swipeObject = new HashMap<String, String>();
swipeObject.put("text", target);
swipeObject.put("direction", direction);
swipeObject.put("element", widID);
js.executeScript("mobile: scrollTo", swipeObject);
wait(200);
}
public static void swipeUpElement(AppiumDriver<MobileElement> driver, MobileElement element, int duration)
{
int topY = element.getLocation().getY();
int bottomY = topY + element.getSize().getHeight();
int centerX = element.getLocation().getX() + (element.getSize().getWidth()/2);
driver.swipe(centerX, bottomY, centerX, topY, duration);
}
But in both these I need element- but on the page I cannot find any element except the webview.I am using UiAutomator to capture the IDs.Any suggestions / link / workaround will be helpful

ELements arent displaced uniquely in web view. U need to develop mathematical logic to get screen size and scroll according to them, use the below code,
public void scroll() throws IOException {
try {
Dimension dimensions = driver.manage().window().getSize();
System.out.println("Size of Window= " +dimension);
int scrollStart = (int) (dimension.getHeight() * 0.5);
System.out.println("Size of scrollStart= " +scrollStart);
int scrollEnd = (int) (dimension.getHeight() * 0.2);
System.out.println("Size of cscrollEnd= " + scrollEnd);
driver.swipe(0,scrollStart,0,scrollEnd,1000);
Application_Log.info("Screen Swiped " );
} catch (IOException e) {
Assert.fail("Swipe failed");
}
}

Try switching to native context driver.context("NATIVE_APP"); before scroll .
If it does not work then give a try for JavascriptExecutor like below sample
MobileElement element = driver.findElement(By.xpath("element-xpath"));
JavascriptExecutor js = (JavascriptExecutor) driver;
HashMap scrollObject = new HashMap();
scrollObject.put("direction", "down");
scrollObject.put("element", element);
js.executeScript("mobile: scroll", scrollObject);

Related

Integrating im2txt model in Android phone

I am new to TensorFlow and cannot find out the solution of these questions.
How can I retrain the im2txt model for my new dataset such that the dataset on which the im2txt model was trained does not get lost and my new dataset is added to the MSCOCO dataset to caption the new images (i.e training dataset= MSCOCO dataset + My new dataset). Someone, please share the detailed procedure and the problems that I can face while retraining.
I have found out the TensorFlow tutorial for running inception V3 model in android on real-time datasets, Can this method be applied as well to the im2txt model i.e. can this be made to caption an image taken from a mobile in real time. Someone, please share the detailed steps how to do this.
After the weeks of struggle can be able to run and execute the im2txt model on Android.
Since I found the solutions from different blogs and different questions and answers, Felt that it might be useful if the all(maximum) solution is at one place.So, Sharing the steps followed.
You need to clone the tensorflow project https://github.com/tensorflow/tensorflow/releases/tag/v1.5.0 in order to freeze the graph and for some more utils.
Downloaded the im2txt model form https://github.com/KranthiGV/Pretrained-Show-and-Tell-model
Followed the steps described in the above link Can able to Run the inference to generate captions on the Linux desktop Successfully after renaming some variable in the graph(to overcome NotFoundError (see above for traceback): Key lstm/basic_lstm_cell/bias not found in checkpoint types of errors)
Now we need to freeze the existing model to obtain the frozen graph in order to use in android/ios
from cloned tensorflow project using freeze_graph.py( tensorflow/tensorflow/blob/master/tensorflow/python/tools/freeze_graph.py) one can freeze the graph from any model by giving the following command
An example of command-line usage is:
bazel build tensorflow/python/tools:freeze_graph && \
bazel-bin/tensorflow/python/tools/freeze_graph \
--input_graph=some_graph_def.pb \
--input_checkpoint=model.ckpt-8361242 \
--output_graph=/tmp/frozen_graph.pb --output_node_names=softmax
--input_binary=true
we need to supply the all the output_node_names which we required to run the model, from "Pretrained-Show-and-Tell-model\im2txt\im2txt\inference_wrapper.py" we can list out the output node names as 'softmax', 'lstm/initial_state' and 'lstm/state'
when I run the freeze graph command by supplying the output node names as 'softmax', 'lstm/initial_state' and 'lstm/state' got the error "AssertionError: softmax is not in the graph"
From the answers for
How to freeze an im2txt model?(How to freeze an im2txt model?)
by Steph and Jeff Tang
The current model ckpt.data, ckpt.index and ckpt.meta files and a graph.pbtxt should be loaded in inference mode (see InferenceWrapper in im2txt). It builds a graph with the correct names 'softmax', 'lstm/initial_state' and 'lstm/state'. You save this graph (with the same ckpt format) and then you can apply the freeze_graph script to obtain the frozen model.
to do this in Pretrained-Show-and-Tell-model\im2txt\im2txt\inference_utils\inference_wrapper.base.py, just add something like saver.save(sess, "model/ckpt4") after saver.restore(sess, checkpoint_path) in def _restore_fn(sess):. Then rebuild and run_inference and you'll get a model that can be frozen, transformed, and optionally memmapped, to be loaded by iOS and Android apps
Now I run the command as below
python tensorflow/python/tools/freeze_graph.py \
--input_meta_graph=/tmp/ckpt4.meta \
--input_checkpoint=/tmp/ckpt4 \
--output_graph=/tmp/ckpt4_frozen.pb \
--output_node_names="softmax,lstm/initial_state,lstm/state" \
--input_binary=true
and loaded the obtained ckpt4_frozen.pb file into the Android application and got the error
"java.lang.IllegalArgumentException: No OpKernel was registered to support Op 'DecodeJpeg' with these attrs. Registered devices: [CPU], Registered kernels:
[[Node: decode/DecodeJpeg = DecodeJpegacceptable_fraction=1, channels=3, dct_method="", fancy_upscaling=true, ratio=1, try_recover_truncated=false]]"
From https://github.com/tensorflow/tensorflow/issues/2883
Since DecodeJpeg isn't supported as part of the Android tensorflow core, you'll need to strip it out of the graph first
bazel build tensorflow/python/tools:strip_unused && \
bazel-bin/tensorflow/python/tools/strip_unused \
--input_graph=ckpt4_frozen.pb \
--output_graph=ckpt4_frozen_stripped_graph.pb \
--input_node_names=convert_image/Cast,input_feed,lstm/state_feed\
--output_node_names=softmax,lstm/initial_state,lstm/state\
--input_binary=true
When I try to load ckpt4_frozen_stripped_graph.pb in android i faced errors so i followed Jeff Tang's answer (Error using Model after using optimize_for_inference.py on frozen graph)
Instead of tools:strip_unused I used graph transformation tool
bazel-bin/tensorflow/tools/graph_transforms/transform_graph \
--in_graph=/tmp/ckpt4_frozen.pb \
--out_graph=/tmp/ckpt4_frozen_transformed.pb \
--inputs="convert_image/Cast,input_feed,lstm/state_feed" \
--outputs="softmax,lstm/initial_state,lstm/state" \
--transforms='
strip_unused_nodes(type=float, shape="1,299,299,3")
fold_constants(ignore_errors=true)
fold_batch_norms
fold_old_batch_norms'
I can able load the obtained ckpt4_frozen_transformed.pb on android successfully.
when I supply the input as float array of RGB image pixels for input node "convert_image/Cast" and fetch the output from "lstm/initail_state" node successfully.
Now the challenge is to understand the beam search in "Pretrained-Show-and-Tell-model\im2txt\im2txt\inference_utils\caption_generator.py" and same should be implemented on the Android side.
If you observe the python script caption_generator.py at
softmax, new_states, metadata = self.model.inference_step(sess,input_feed,state_feed)
input_feed is an int32 bit array and state_feed is a multidimensional float array
on the android side, I tried feeding int32 bit array for "input_feed", since there is no Java API to feed multidimensional array so I fed float array to lstm/state_feed as it is which fetched previously from "lstm/initail_state" node.
Got two errors one is for the input_fedd is expecting int 64bit and
"java.lang.IllegalArgumentException: -input rank(-1) <= split_dim < input rank (1), but got 1" at lstm/state_feed.
For the first error, I changed the input_feed feed data type from int32 to int 64.
About second error it is expecting rank two tensor.
If you see tensorflow java sources the data type float array which we are feeding is converted to a rank one tensor, we should feed data type in such a way that rank two tensor should be created but at present, I didn't find any API to feed multidimensional float array there
When I browsing tensorflow java source I found the API which was not exposed as Android API where we can create a rank two tensor. so I rebuilt and both libtensorflow_inference.so and libandroid_tensorflow_inference_java.jar by enabling the rank two tensor creation call.(for building process refer https://blog.mindorks.com/android-tensorflow-machine-learning-example-ff0e9b2654cc)
Now I can able to run the inference on Android and get the one caption for the image.But the accuracy very low.
Reason limiting for the one caption is I didn't find a way to fetch the outputs as a multidimensional array which is required for generating more number of cations for a single image.
String actualFilename = labelFilename.split("file:///android_asset/")[1];
vocab = new Vocabulary(assetManager.open(actualFilename));
inferenceInterface = new TensorFlowInferenceInterface(assetManager, modelFilename);
final Graph g = c.inferenceInterface.graph();
final Operation inputOperation = g.operation(inputName);
if (inputOperation == null) {
throw new RuntimeException("Failed to find input Node '" + inputName + "'");
}
final Operation outPutOperation = g.operation(outputName);
if (outPutOperation == null) {
throw new RuntimeException("Failed to find output Node '" + outputName + "'");
}
// The shape of the output is [N, NUM_CLASSES], where N is the batch size.
int numClasses = (int) inferenceInterface.graph().operation(outputName)
.output(0).shape().size(1);
Log.i(TAG, "Read " + vocab.totalWords() + " labels, output layer size is " + numClasses);
// Ideally, inputSize could have been retrieved from the shape of the input operation. Alas,
// the placeholder node for input in the graphdef typically used does not specify a shape, so it
// must be passed in as a parameter.
inputSize = inputSize;
// Pre-allocate buffers.
outputNames = new String[]{outputName + ":0"};
outputs = new float[numClasses];
inferenceInterface.feed(inputName + ":0", pixels, inputSize, inputSize, 3);
inferenceInterface.run(outputNames, runStats);
inferenceInterface.fetch(outputName + ":0", outputs);
startIm2txtBeamSearch(outputs);
//Implemented Beam search in JAVA
private void startIm2txtBeamSearch(float[] outputs) {
int beam_size = 1;
//TODO:Prepare vocab ids from file
ArrayList<Integer> vocab_ids = new ArrayList<>();
vocab_ids.add(1);
int vocab_end_id = 2;
float lenth_normalization_factor = 0;
int maxCaptionLength = 20;
Graph g = inferenceInterface.graph();
//node input feed
String input_feed_node_name = "input_feed";
Operation inputOperation = g.operation(input_feed_node_name);
if (inputOperation == null) {
throw new RuntimeException("Failed to find input Node '" + input_feed_node_name + "'");
}
String output_feed_node_name = "softmax";
Operation outPutOperation = g.operation(output_feed_node_name);
if (outPutOperation == null) {
throw new RuntimeException("Failed to find output Node '" + output_feed_node_name + "'");
}
int output_feed_node_numClasses = (int) outPutOperation.output(0).shape().size(1);
Log.i(TAG, "Output layer " + output_feed_node_name + ", output layer size is " + output_feed_node_numClasses);
FloatBuffer output_feed_output = FloatBuffer.allocate(output_feed_node_numClasses);
//float [][] output_feed_output = new float[numClasses][];
//node state feed
String input_state_feed_node_name = "lstm/state_feed";
inputOperation = g.operation(input_state_feed_node_name);
if (inputOperation == null) {
throw new RuntimeException("Failed to find input Node '" + input_state_feed_node_name + "'");
}
String output_state_feed_node_name = "lstm/state";
outPutOperation = g.operation(output_state_feed_node_name);
if (outPutOperation == null) {
throw new RuntimeException("Failed to find output Node '" + output_state_feed_node_name + "'");
}
int output_state_feed_node_numClasses = (int) outPutOperation.output(0).shape().size(1);
Log.i(TAG, "Output layer " + output_state_feed_node_name + ", output layer size is " + output_state_feed_node_numClasses);
FloatBuffer output_state_output = FloatBuffer.allocate(output_state_feed_node_numClasses);
//float[][] output_state_output= new float[numClasses][];
String[] output_nodes = new String[]{output_feed_node_name, output_state_feed_node_name};
Caption initialBean = new Caption(vocab_ids, outputs, (float) 0.0, (float) 0.0);
TopN partialCaptions = new TopN(beam_size);
partialCaptions.push(initialBean);
TopN completeCaption = new TopN(beam_size);
captionLengthLoop:
for (int i = maxCaptionLength; i >= 0; i--) {
List<Caption> partialCaptionsList = new LinkedList<>(partialCaptions.extract(false));
partialCaptions.reset();
long[] input_feed = new long[partialCaptionsList.size()];
float[][] state_feed = new float[partialCaptionsList.size()][];
for (int j = 0; j < partialCaptionsList.size(); j++) {
Caption curCaption = partialCaptionsList.get(j);
ArrayList<Integer> senArray = curCaption.getSentence();
input_feed[j] = senArray.get(senArray.size() - 1);
state_feed[j] = curCaption.getState();
}
//feeding
inferenceInterface.feed(input_feed_node_name, input_feed, new long[]{input_feed.length});
inferenceInterface.feed(input_state_feed_node_name, state_feed, new long[]{state_feed.length});
//run
inferenceInterface.run(output_nodes, runStats);
//fetching
inferenceInterface.fetch(output_feed_node_name, output_feed_output);
inferenceInterface.fetch(output_state_feed_node_name, output_state_output);
float[] word_probabilities = new float[partialCaptionsList.size()];
float[] new_state = new float[partialCaptionsList.size()];
for (int k = 0; k < partialCaptionsList.size(); k++) {
word_probabilities = output_feed_output.array();
//output_feed_output.get(word_probabilities[k]);
new_state = output_state_output.array();
//output_feed_output.get(state[k]);
// For this partial caption, get the beam_size most probable next words.
Map<Integer, Float> word_and_probs = new LinkedHashMap<>();
//key is index of probability; value is index = word
for (int l = 0; l < word_probabilities.length; l++) {
word_and_probs.put(l, word_probabilities[l]);
}
//sorting
// word_and_probs = word_and_probs.entrySet().stream()
// .sorted(Map.Entry.comparingByValue())
// .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,(e1, e2) -> e1, LinkedHashMap::new));
word_and_probs = MapUtil.sortByValue(word_and_probs);
//considering first (beam size probabilities)
LinkedHashMap<Integer, Float> final_word_and_probs = new LinkedHashMap<>();
for (int key : word_and_probs.keySet()) {
final_word_and_probs.put(key, word_and_probs.get(key));
if (final_word_and_probs.size() == beam_size)
break;
}
for (int w : final_word_and_probs.keySet()) {
float p = final_word_and_probs.get(w);
if (p < 1e-12) {//# Avoid log(0).
Log.d(TAG, "p is < 1e-12");
continue;
}
Caption partialCaption = partialCaptionsList.get(k);
ArrayList<Integer> sentence = new ArrayList<>(partialCaption.getSentence());
sentence.add(w);
float logprob = (float) (partialCaption.getPorb() + Math.log(p));
float scroe = logprob;
Caption beam = new Caption(sentence, new_state, logprob, scroe);
if (w == vocab_end_id) {
completeCaption.push(beam);
} else {
partialCaptions.push(beam);
}
}
if (partialCaptions.getSize() == 0)//run out of partial candidates; happens when beam_size = 1.
break captionLengthLoop;
}
//clear buffer retrieve sub sequent output
output_feed_output.clear();
output_state_output.clear();
output_feed_output = null;
output_state_output = null;
output_feed_output = FloatBuffer.allocate(output_feed_node_numClasses);
output_state_output = FloatBuffer.allocate(output_state_feed_node_numClasses);
Log.d(TAG, "----" + i + " Iteration completed----");
}
Log.d(TAG, "----Total Iterations completed----");
LinkedList<Caption> completeCaptions = completeCaption.extract(true);
for (Caption cap : completeCaptions) {
ArrayList<Integer> wordids = cap.getSentence();
StringBuffer caption = new StringBuffer();
boolean isFirst = true;
for (int word : wordids) {
if (!isFirst)
caption.append(" ");
caption.append(vocab.getWord(word));
isFirst = false;
}
Log.d(TAG, "Cap score = " + Math.exp(cap.getScore()) + " and Caption is " + caption);
}
}
//Vocab
public class Vocabulary {
String TAG = Vocabulary.class.getSimpleName();
String start_word = "<S>", end_word = "</S>", unk_word = "<UNK>";
ArrayList<String> words;
public Vocabulary(File vocab_file) {
loadVocabsFromFile(vocab_file);
}
public Vocabulary(InputStream vocab_file_stream) {
words = readLinesFromFileAndLoadWords(new InputStreamReader(vocab_file_stream));
}
public Vocabulary(String vocab_file_path) {
File vocabFile = new File(vocab_file_path);
loadVocabsFromFile(vocabFile);
}
private void loadVocabsFromFile(File vocabFile) {
try {
this.words = readLinesFromFileAndLoadWords(new FileReader(vocabFile));
//Log.d(TAG, "Words read from file = " + words.size());
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
private ArrayList<String> readLinesFromFileAndLoadWords(InputStreamReader file_reader) {
ArrayList<String> words = new ArrayList<>();
try (BufferedReader br = new BufferedReader(file_reader)) {
String line;
while ((line = br.readLine()) != null) {
// process the line.
words.add(line.split(" ")[0].trim());
}
br.close();
if (!words.contains(unk_word))
words.add(unk_word);
} catch (IOException e) {
e.printStackTrace();
}
return words;
}
public String getWord(int word_id) {
if (words != null)
if (word_id >= 0 && word_id < words.size())
return words.get(word_id);
return "No word found, Maybe Vocab File not loaded";
}
public int totalWords() {
if (words != null)
return words.size();
return 0;
}
}
//MapUtil
public class MapUtil {
public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue(Map<K, V> map) {
List<Map.Entry<K, V>> list = new ArrayList<>(map.entrySet());
list.sort(new Comparator<Map.Entry<K, V>>() {
#Override
public int compare(Map.Entry<K, V> o1, Map.Entry<K, V> o2) {
if (o1.getValue() instanceof Float && o2.getValue() instanceof Float) {
Float o1Float = (Float) o1.getValue();
Float o2Float = (Float) o2.getValue();
return o1Float >= o2Float ? -1 : 1;
}
return 0;
}
});
Map<K, V> result = new LinkedHashMap<>();
for (Map.Entry<K, V> entry : list) {
result.put(entry.getKey(), entry.getValue());
}
return result;
}
}
//Caption
public class Caption implements Comparable<Caption> {
private ArrayList<Integer> sentence;
private float[] state;
private float porb;
private float score;
public Caption(ArrayList<Integer> sentence, float[] state, float porb, float score) {
this.sentence = sentence;
this.state = state;
this.porb = porb;
this.score = score;
}
public ArrayList<Integer> getSentence() {
return sentence;
}
public void setSentence(ArrayList<Integer> sentence) {
this.sentence = sentence;
}
public float[] getState() {
return state;
}
public void setState(float[] state) {
this.state = state;
}
public float getPorb() {
return porb;
}
public void setPorb(float porb) {
this.porb = porb;
}
public float getScore() {
return score;
}
public void setScore(float score) {
this.score = score;
}
#Override
public int compareTo(#NonNull Caption oc) {
if (score == oc.score)
return 0;
if (score < oc.score)
return -1;
else
return 1;
}
}
//TopN
public class TopN {
//Maintains the top n elements of an incrementally provided set.
int n;
LinkedList<Caption> data;
public TopN(int n) {
this.n = n;
this.data = new LinkedList<>();
}
public int getSize() {
if (data != null)
return data.size();
return 0;
}
//Pushes a new element
public void push(Caption x) {
if (data != null) {
if (getSize() < n) {
data.add(x);
} else {
data.removeLast();
data.add(x);
}
}
}
//Extracts all elements from the TopN. This is a destructive operation.
//The only method that can be called immediately after extract() is reset().
//Args:
//sort: Whether to return the elements in descending sorted order.
//Returns: A list of data; the top n elements provided to the set.
public LinkedList<Caption> extract(boolean sort) {
if (sort) {
Collections.sort(data);
}
return data;
}
//Returns the TopN to an empty state.
public void reset() {
if (data != null) data.clear();
}
}
Even though accuracy is very low I am sharing this because it might be useful for some to load the show and tell models in android.

Using an arraylist for multiple if conditions

I changed my mind about using swipemotions: As it is rather complicated to use swipemotions, I decided to just use simple buttons with 'bigger' and 'smaller'
I'm currently working on a school project in Android Studio and so far I've written a code which generates a random equation.
Here is the code which gereates the random equation:
String[] operationSet = new String[]{"+", "-", "/", "*"};
String stringResultOfEquation;
String equation;
double doubleAnswer1;
public void start1() {
Random random = new Random();
int numOfOperations = random.nextInt(2) + 1;
List<String> operations = new ArrayList<>();
for (int i = 0; i < numOfOperations; i++) {
String operation = operationSet[random.nextInt(4)];
operations.add(operation);
}
int numOfNumbers = numOfOperations + 1;
List<Integer> numbers = new ArrayList<>();
for (int i = 0; i < numOfNumbers; i++) {
int number = random.nextInt(10)+1;
numbers.add(number);
}
String equation = "";
for (int i = 0; i < numOfOperations; i++) {
equation += numbers.get(i);
equation += operations.get(i);
}
equation += numbers.get(numbers.size() -1);
TextView TextEquation = (TextView)findViewById(R.id.textView3);
TextEquation.setText(equation);
String stringResultOfEquation = String.valueOf(equation);
double doubleAnswer1 = eval(stringResultOfEquation);
String stringAnswer = Double.toString(doubleAnswer1);
TextView textAnswer = (TextView)findViewById(R.id.textView4);
textAnswer.setText(stringAnswer);
}
Now the app displays two equations on the screen and the user then has to dicide wether the second equation has a bigger or smaller result than the first one. If the second equation is bigger, the user has to do a swipemotion UP and if the second equation is smaller, the user has to do a swipemotion DOWN.
However I don't know how to write the code for this. I tried this:
if((doubleAnswer1 > doubleAnswer2) && (MotionEvent.ACTION_DOWN = true)){
//create new equation
}
but that didn't work. It told me that "Operator && can't be applied to boolean, int"
Now I'm curious if I could use an arraylist like this:
if(doubleAnswer1 > doubleAnswer2){
// put "smaller" to arraylist
} else {
// put "bigger" to arraylist
}
if(MotionEvent.ACTION_DOWN = true){
// put "smaller" to arraylist
}
if(MotionEvent.ACTION_UP = true){
// put "bigger" to arraylist
}
Then the code would check the arraylist if the elemnts of the arraylist are the same. If so, the next equation will be generated. If the elemnts of the arraylist are different, the process will be stopped.
I really don't know if that would work, so could someone maybe tell me if?
Or is there an other way to solve my problem?
If anything is unclear in my question, feel free to ask and I will try to clarify the problem :)
Thank you already in advance for your help!
When you write such statement editor will tell you (Android studio hope so) that you can't compare int with boolean. as it is tendency that zero means false and 1 means true but in java you can't do like that.
you can try like this
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN)
{
return false;
}
return false;
}
Hope will help in understanding...
"=" is an assignment,
for comparing a value use "==".
regarding recognizing gesture, check out https://developer.android.com/training/gestures/detector.html#detect and https://developer.android.com/reference/android/view/GestureDetector.html
You need something like this:
#Override
public void onCreate(Bundle savedInstanceState) {
...
mDetector = new GestureDetectorCompat(this,this);
...
}
#Override
public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) {
Log.d(TAG, "fling! - direction is " + (velocityY > 0 ? "down" : "up"));
return true;
}

swipe or scroll to bottom in appium - android

How can I swipe scroll to bottom in an android app using appium?
I tried using
driver.swipe(300,800,300,500,2);
driver.scrollTo("string")
But above did not helped. Can anyone suggest me some generic solution ?
A generic solution will be scrolling using dimensions. use the below code
public void scroll() throws IOException {
try {
Dimension dimensions = driver.manage().window().getSize();
System.out.println("Size of screen= " +dimensions);
int Startpoint = (int) (dimensions.getHeight() * 0.5);
System.out.println("Size of scrollStart= " +Startpoint );
int scrollEnd = (int) (dimensions.getHeight() * 0.2);
System.out.println("Size of cscrollEnd= " + scrollEnd);
driver.swipe(0, Startpoint,0,scrollEnd,1000);
} catch (IOException e) {
}
}
add this to ur code and simply use scroll(); in ur test case. Modify the decimal values given in the code to nmeet your requirements

Realm used like a LinkedList in Android

I have a Realm database of sensor values with the following constructor:
public DataEntry(float x, float y, float z, long timestamp, int xIndex, String xValue) {
this.x = x;
this.y = y;
this.z = z;
this.xIndex = xIndex;
this.timestamp = timestamp;
this.xValue = xValue;
}
I would like this database to be a fixed size of a 100 points. I have this working in a LinkedList approach where I delete the first entry and add one to the end resulting in a fixed size then I use MPChartLib to plot. This is what I would like to mimic using a Realm database.
My approach is to first delete the first entry using the code below:
private void removeFirst(){
RealmResults<DataEntry> result1 = mRealm.where(DataEntry.class).findAll();
mRealm.beginTransaction();
Log.i(TAG, "remove the first element of the database ");
DataEntry first =result1.first();
first.removeFromRealm();
Log.i(TAG, "shift the indexes of the database by one " + result1.size());
for (int i = 0; i < result1.size(); i++) {
DataEntry u = result1.get(i);
int index = u.getxIndex();
u.setxIndex(index - 1);
String xValue = "" +index;
u.setxValue(xValue);
}
mRealm.commitTransaction();
}
Then I add a new data point from acquired data
#Subscribe
public void onSensorUpdatedEvent(SensorUpdatedEvent event) {
if (event.getSensor().getId() == this.sensor.getId()) {
// Log.i(TAG, "remove the first element of the database ");
removeFirst();
mRealm.beginTransaction();
DataEntry entry = mRealm.createObject(DataEntry.class);
// Log.i(TAG, "in database update event with index = " + nextIndex);
entry.setxIndex(nextIndex);
entry.setxValue("" + nextIndex);
nextIndex++;
entry.setAndroidDevice(mAndroidId);
entry.setTimestamp(event.getDataPoint().getTimestamp());
currT.setText(precsion.format(event.getDataPoint().getTimestamp()));
if (event.getDataPoint().getValues().length > 0) {
entry.setX(event.getDataPoint().getValues()[0]);
currX.setText(precsion.format(event.getDataPoint().getValues()[0]));
} else {
entry.setX(0.0f);
}
if (event.getDataPoint().getValues().length > 1) {
entry.setY(event.getDataPoint().getValues()[1]);
currY.setText(precsion.format(event.getDataPoint().getValues()[1]));
} else {
entry.setY(0.0f);
}
if (event.getDataPoint().getValues().length > 2) {
entry.setZ(event.getDataPoint().getValues()[2]);
currZ.setText(precsion.format(event.getDataPoint().getValues()[2]));
} else {
entry.setZ(0.0f);
}
deltaT.setText(precsion.format((event.getDataPoint().getTimestamp() - lastT) / scaleT));
lastT = event.getDataPoint().getTimestamp();
entry.setAccuracy(event.getDataPoint().getAccuracy());
mRealm.commitTransaction();
}
}
MPChartLib uses the xIndex to establish position along the x axis so I change these values as part of the removeFirst class. My results in MpChartLib do not give me the desired result. I may be using it beyond its application or I may not be using the Realm in the the correct manner.
What sort of makes sense is to start with 100 blank database entries then fill them one at a time until I've reached 100 then "shift" entries such that entry 1 becomes entry 0, entry 99 becomes 98 and I update entry 99 with the new data.
While I think this might work it seems very inefficient to shift values of 100 fixed database points.
I would rather prefer to delete the first one and add a new one at the end like I can do with a LinkedList.
Kind of lost as to how to proceed. Any assistance is greatly appreciated.
RealmQuery.findAll() won't give you a stable order of the results. You need to sort the results based on some fields to achieve that.
I think what you can do is combining using #PrimaryKey and RealmQuery.max().
public class DataEntry {
#PrimaryKey
private long id;
// ...
}
private void addEntry(DataEntry entry){
realm.beginTransaction();
RealmResults<DataEntry> results = realm.where(DataEntry.class).findAllSorted("id");
if (results.count.size() >= 100) {
// Remove the first entry
results.get(0).removeFromRealm();
}
// NOTE: Consider the integer overflow and the empty results here!!!!
entry.setId(restuls.max("id").longValue() + 1;
realm.copyToRealm(entry);
realm.commitTransaction();
}
The id won't be in range [1-100] but i believe you can do some math to achieve that.
Using the Primary key and sorting as beeender recommends works. I modified the timestamp as the primary key and included a string version of the timestamp which MPChartLib seems to require.
So my DataEntry Realm database
#RealmClass
public class DataEntry extends RealmObject {
private String sTimestamp;
private String androidDevice;
private float x;
private float y;
private float z;
private int accuracy;
#PrimaryKey
private long timestamp;
// no arguments constructor for Realm database
public DataEntry() {
}
public DataEntry(float x, float y, float z, long timestamp, String sTimestamp) {
this.x = x;
this.y = y;
this.z = z;
this.timestamp = timestamp;
this.sTimestamp = sTimestamp;
}
And the code for updating the database:
#Subscribe
public void onSensorUpdatedEvent(SensorUpdatedEvent event) {
if (event.getSensor().getId() == this.sensor.getId()) {
mRealm.beginTransaction();
RealmResults<DataEntry> results = mRealm.
where(DataEntry.class).findAllSorted("timestamp");
if (results.size() == 1) {
startTime = results.get(0).getTimestamp();
// Log.i(TAG, "first data received: startTime " + startTime);
}
// Log.i(TAG, "check size of the database " +results.size());
if (results.size() >= 100) {
// Log.i(TAG, "remove the first element of the database ");
results.get(0).removeFromRealm();
}
// Log.i(TAG, "create element for the database ");
DataEntry entry = mRealm.createObject(DataEntry.class);
entry.setAndroidDevice(mAndroidId);
long mTime = (long) (event.getDataPoint().getTimestamp()-startTime );
// Log.i(TAG, "time set at = " +mTime);
entry.setTimestamp(mTime);
// currT.setText(precsion.format(mTime));
entry.setsTimestamp(String.valueOf(mTime));
if (event.getDataPoint().getValues().length > 0) {
entry.setX(event.getDataPoint().getValues()[0]);
currX.setText(precsion.format(event.getDataPoint().getValues()[0]));
} else {
entry.setX(0.0f);
}
if (event.getDataPoint().getValues().length > 1) {
entry.setY(event.getDataPoint().getValues()[1]);
currY.setText(precsion.format(event.getDataPoint().getValues()[1]));
} else {
entry.setY(0.0f);
}
if (event.getDataPoint().getValues().length > 2) {
entry.setZ(event.getDataPoint().getValues()[2]);
currZ.setText(precsion.format(event.getDataPoint().getValues()[2]));
} else {
entry.setZ(0.0f);
}
deltaT.setText(precsion.format((event.getDataPoint().getTimestamp() - lastT) / scaleT));
totalT = ((event.getDataPoint().getTimestamp() - lastT ) / scaleT) * results.size()/1000;
totalTText.setText(String.valueOf(totalT));
lastT = event.getDataPoint().getTimestamp();
entry.setAccuracy(event.getDataPoint().getAccuracy());
// Log.i(TAG, "copy element to the database ");
mRealm.copyToRealm(entry);
// Log.i(TAG, " database has size = " + results.size());
mRealm.commitTransaction();
}
}
Then set the data into MPChartLib format
private void setData() {
// Log.i(TAG, "In setData perform database query , sort by timestamp");
RealmResults<DataEntry> result1 = mRealm.where(DataEntry.class).findAllSorted("timestamp");
// Log.i(TAG, "set Database size is = " + result1.size());
// Log.i(TAG, "Extract x data ");
RealmLineDataSet<DataEntry> set1 = new RealmLineDataSet<>(result1, "x");
set1.setDrawCubic(false);
set1.setLabel("Realm X");
set1.setDrawCircleHole(false);
set1.setColor(ColorTemplate.rgb("#FF5722"));
set1.setCircleColor(ColorTemplate.rgb("#FF5722"));
set1.setLineWidth(1.8f);
set1.setCircleSize(3.6f);
// Log.i(TAG, "Extract y data ");
RealmLineDataSet<DataEntry> set2 = new RealmLineDataSet<>(result1, "y");
set1.setDrawCubic(false);
set1.setLabel("Realm Y");
set1.setDrawCircleHole(false);
set1.setColor(ColorTemplate.rgb("#FF5722"));
set1.setCircleColor(ColorTemplate.rgb("#FF5722"));
set1.setLineWidth(1.8f);
set1.setCircleSize(3.6f);
// Log.i(TAG, "Extract z data ");
RealmLineDataSet<DataEntry> set3 = new RealmLineDataSet<>(result1, "z");
set1.setDrawCubic(false);
set1.setLabel("Realm Z");
set1.setDrawCircleHole(false);
set1.setColor(ColorTemplate.rgb("#FF5722"));
set1.setCircleColor(ColorTemplate.rgb("#FF5722"));
set1.setLineWidth(1.8f);
set1.setCircleSize(3.6f);
// Log.i(TAG, "add datasets ");
ArrayList<ILineDataSet> dataSets = new ArrayList<>();
dataSets.add(set1);
dataSets.add(set2);
dataSets.add(set3);
// Log.i(TAG, "Create Line Data for graphing " );
RealmLineData lineData = new RealmLineData(result1, "sTimestamp", dataSets);
// Log.i(TAG, "Set Data on Chart ");
mChart.setData(lineData);
// Log.i(TAG, "Re-draw ");
mChart.invalidate();
}
I'm ok with not having x-axis labels as they are huge numbers. my plan is to shut off the axis labels.

Android Phrase o-matic

I'd like to port this little program to Android, thing is that im level basic -1 at android, what the program does is that it randomly creates a phrase taken from strings in an array. I know how to make a button to show me an xml from the layout resources but thatjust works with textviews that do not change, Could you please tell me which steps to follow in order to display a randomly generated string taken from the array of strings?
heres the code(head first java):
public class PhraseOMatic
{
public static void main (String[] args)
{
String[] wordListOne = {"24/7", "multi-tier", "30,OOO foot", "B-to-B" , "win-win" , "frontend", "web- based" , "pervasive", "smart", "sixsigma", "critical-path", "dynamic"};
String[] wordListTwo = {"empowered", "sticky", "value-added", "oriented", "centric", "distributed", "clustered", "branded", "outaide-the-box", "positioned", "networked", "focused", "leveraged", "aligned", "targeted", "shared", "cooperative", "accelerated"};
String[] wordListThree = {"process", "tipping-point", "solution", "architecture", "core competency", "strategy", "mindshare", "portal", "space", "vision", "paradigm", "session"};
// find out how many words are in each list
int oneLenqth = wordListOne.length;
int twoLength = wordListTwo.length;
int threeLength = wordListThree.length;
// generate .... random numbers
int randl = (int) (Math.random() * oneLenqth);
int rand2 = (int) (Math.random() * twoLength);
int rand3 = (int) (Math.random() * threeLength);
//now build a phrase
String phrase = wordListOne[randl] + " " + wordListTwo[rand2] + " " + wordListThree[rand3];
// print out the phrase
System.out.println("What we need is a " + phrase);
}
}

Categories

Resources