This code work perfectly but i can't make work with ANDROID, i need to comapre two image ?
import java.awt.image.BufferedImage;
import java.io.FileInputStream;
import java.util.Vector;
import javax.imageio.ImageIO;
public class Untitled1 {
public static void main(String[] args) {
Vector original = testImg("b.jpg");
Vector clonde = testImg("a.jpg");
System.out.println(original.equals(clonde));
}
public static Vector testImg(String file) {
Vector all = new Vector();
try {
BufferedImage im = ImageIO.read(new FileInputStream(file));
int w = im.getWidth(null);
int h = im.getHeight(null);
int[] rgbs = new int[w * h];
int x = 0;
im.getRGB(0, 0, w, h, rgbs, 0, w);
for (int i = 0; i < w; i+=100) {
Vector line = new Vector();
for (int j = 0; j < h; j+=100) {
line.add(new Integer(rgbs[x]));
// System.out.println("Pixel " + i + "," + j + "has " + "RGB values of " + rgbs[x]);
x++;
}
all.add(line);
}
} catch (Exception ex) {
ex.printStackTrace();
}
return all;
}
}
a couple of things:
you should be returning true from onOptionsItemSelected() if your code handles the selected menu option, and false if it doesn't.
you should break your loop as soon as you determine the images are different. Why do more work than you need to?
there is no need to use a case/switch here. You only handle a single menu item.
so:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() != 1000)
return (super.onOptionsItemSelected(item);
for(int i=0;i<tabA.length;i++)
{
if(tabA[i] != tabB[i])
{
Toast.makeText(this, "Image are not equal", Toast.LENGTH_LONG).show();
return (true);
}
}
Toast.makeText(this, "Image are equal", Toast.LENGTH_LONG).show();
return (true);
}
Related
I can display the information of my phone application but I am restricted to display only six.
I would like to know how to proceed to display the rest of the elements ( i have a list of 17 elements).
For the moment I use the first and last columns of my Template to do an invalidate() and display the previous or next items of my list
public Template onGetTemplate() {
ListTemplate.Builder templateBuilder = new ListTemplate.Builder();
ItemList.Builder sectionABuilder = new ItemList.Builder();
if(compteur < 4 ) {
try {
if (DataMgr.getInstance().getDataListAdress().size() > 0 && compteur < DataMgr.getInstance().getDataListAdress().get(0).length) {
for (int i = compteur; i < compteur + 5; i++) {
System.out.println("////Test + " + DataMgr.getInstance().getDataListAdress().get(0)[i]);
System.out.println("////TestLength + " + DataMgr.getInstance().getDataListAdress().get(0).length);
sectionABuilder.addItem(buildRow(DataMgr.getInstance().getDataListAdress().get(0)[i]));
}
}
sectionABuilder.addItem(buildRowClick("Suivant"));
templateBuilder.addSectionedList(
SectionedItemList.create(sectionABuilder.build(), "Header"));
} catch (Exception e) {
CarToast.makeText(getCarContext(), "No more", CarToast.LENGTH_SHORT).show();
}
} else {
sectionABuilder.addItem(buildRowClickPrecedent("Precedent"));
try {
if (DataMgr.getInstance().getDataListAdress().size() > 0 && compteur < DataMgr.getInstance().getDataListAdress().get(0).length) {
for (int i = compteur; i < compteur + 4; i++) {
System.out.println("////Test + " + DataMgr.getInstance().getDataListAdress().get(0)[i]);
System.out.println("////Test +" + DataMgr.getInstance().getDataListAdress().get(0).length);
sectionABuilder.addItem(buildRow(DataMgr.getInstance().getDataListAdress().get(0)[i]));
}
}
sectionABuilder.addItem(buildRowClick("Suivant"));
templateBuilder.addSectionedList(
SectionedItemList.create(sectionABuilder.build(), "Header"));
} catch (Exception e) {
CarToast.makeText(getCarContext(), "No more", CarToast.LENGTH_SHORT).show();
}
}
return templateBuilder
.setHeaderAction(Action.PAN)
.setTitle("ok")
.build();
}
#NonNull
private Row buildRow(String data) {
return new Row.Builder()
.setTitle(data)
.build();
}
#NonNull
private Row buildRowClick(String data) {
return new Row.Builder()
.setOnClickListener(new OnClickListener() {
#Override
public void onClick() {
compteur += 4;
invalidate();
}
})
.setTitle(data)
.build();
}
You can't use it like this. Use ConstraintManager.class.
Lists are limited by unit you have in a car. But there is special API to handle this.
Check ConstraintManager:
int listLimit = Math.min(MAX_LIST_ITEMS,
getCarContext().getCarService(ConstraintManager.class).getContentLimit(
ConstraintManager.CONTENT_LIMIT_TYPE_LIST));
Docs: https://developer.android.com/reference/androidx/car/app/constraints/ConstraintManager
You can take this limit count and interate your list only based on this number.
I'm using custom TileProviders in my Android app to display offline maps and OpenStreetMap maps. It works, but there is a problem with the tiles resolution, which is quite bad. The files have a size of 256x256, and setting the width/height of my TileProvider to 128 doesn't change anything.
Here is some piece of code :
public class GenericUrlTileProvider extends UrlTileProvider {
// ---------------------------------------------------------------------------------------
// Private attributes :
private String _baseUrl;
// ---------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------
// Constructor :
public GenericUrlTileProvider(int width, int height, String url) {
super(width, height);
this._baseUrl = url;
}
#Override
public URL getTileUrl(int x, int y, int zoom) {
try {
return new URL(_baseUrl.replace("{z}", "" + zoom).replace("{x}", "" + x).replace("{y}", "" + y));
}
catch (MalformedURLException e) { e.printStackTrace(); }
return null;
}
// ---------------------------------------------------------------------------------------
}
Does anyone know how to fix this to support high resolution devices ?
Thanks
On #grub request, here is what I did for getting the 4 tiles of the next zoom level :
public Tile getTileFromNextZoomLevel(int x, int y, int zoom) {
final String topLeftTileUrl = _source.getUrlSchema().replace("{z}", "" + (zoom + 1)).replace("{x}", "" + (x * 2)).replace("{y}", "" + (y * 2));
final String topRightTileUrl = _source.getUrlSchema().replace("{z}", "" + (zoom + 1)).replace("{x}", "" + (x * 2 + 1)).replace("{y}", "" + (y * 2));
final String bottomLeftTileUrl = _source.getUrlSchema().replace("{z}", "" + (zoom + 1)).replace("{x}", "" + (x * 2)).replace("{y}", "" + (y * 2 + 1));
final String bottomRightTileUrl = _source.getUrlSchema().replace("{z}", "" + (zoom + 1)).replace("{x}", "" + (x * 2 + 1)).replace("{y}", "" + (y * 2 + 1));
final Bitmap[] tiles = new Bitmap[4];
Thread t1 = new Thread() {
#Override
public void run() { tiles[0] = Utils.getBitmapFromURL(topLeftTileUrl); }
};
t1.start();
Thread t2 = new Thread() {
#Override
public void run() { tiles[1] = Utils.getBitmapFromURL(topRightTileUrl); }
};
t2.start();
Thread t3 = new Thread() {
#Override
public void run() { tiles[2] = Utils.getBitmapFromURL(bottomLeftTileUrl); }
};
t3.start();
Thread t4 = new Thread() {
#Override
public void run() { tiles[3] = Utils.getBitmapFromURL(bottomRightTileUrl); }
};
t4.start();
try {
t1.join();
t2.join();
t3.join();
t4.join();
}
catch (InterruptedException e) { e.printStackTrace(); }
byte[] tile = Utils.mergeBitmaps(tiles, Bitmap.CompressFormat.JPEG); // PNG is a lot slower, use it only if you really need to
return tile == null ? TileProvider.NO_TILE : new Tile( (int) _source.getTileSize().getWidth(), (int) _source.getTileSize().getHeight(), tile);
}
And the Utils methods :
public static byte[] mergeBitmaps(Bitmap[] parts, Bitmap.CompressFormat format) {
// Check if all the bitmap are null (if so return null) :
boolean allNulls = true;
for (int i = 0; i < parts.length; i++) {
if(parts[i] != null) {
allNulls = false;
break;
}
}
if(allNulls) return null;
Bitmap tileBitmap = Bitmap.createBitmap(512, 512, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(tileBitmap);
Paint paint = new Paint();
for (int i = 0; i < parts.length; i++) {
if(parts[i] == null) {
parts[i] = Bitmap.createBitmap(256, 256, Bitmap.Config.ARGB_8888);
}
canvas.drawBitmap(parts[i], parts[i].getWidth() * (i % 2), parts[i].getHeight() * (i / 2), paint);
}
ByteArrayOutputStream stream = new ByteArrayOutputStream();
tileBitmap.compress(format, 100, stream);
byte[] bytes = stream.toByteArray();
return bytes;
}
public static Bitmap getBitmapFromURL(String urlString) {
try {
// Ensure the file exists :
if(Utils.getResponseCode(urlString) != 200) return null;
URL url = new URL(urlString);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
Bitmap bitmap = BitmapFactory.decodeStream(connection.getInputStream());
return bitmap;
}
catch (IOException e) { return null; }
}
You may have to adapt it for your needs. Please note that my app is still under development, and this code may need some tests / improvements.
package com.example.intracollegeapp;// package name
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.security.MessageDigest;
import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.PropertyInfo;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;
import LibPack.UserInfoLib;
import android.R.string;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import android.support.v4.app.NavUtils;
public class LoginForm extends Activity {
Button login;
TextView username;
TextView password;
UserInfoLib ui;
long msgLength;
long bitLength;
char msg[];
long requiredBits;
long requiredBytes;
int toPad[];
private static final String NAMESPACE = "link to server package on which webservices are stored";
private static final String URL = "link to wsdl file stored on server";
private static final String SOAP_ACTION = "IntraCollegeWS";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login_form);
login=(Button)findViewById(R.id.butLogin);
username=(TextView)findViewById(R.id.editText1);
password=(TextView)findViewById(R.id.editText2);
login.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
ui= new UserInfoLib();
ui.userId=username.getText().toString();
ui.password=getSHA1(password.getText().toString());
ui=(UserInfoLib)callService(objectToString(ui), "UserLogin", "userInfo");
//ui=(UserInfoLib)stringToObject(temp);
if(ui.firstName.equals("")){
Toast.makeText(v.getContext(), "Please Verify User Name Or Password", Toast.LENGTH_LONG).show();
finish();
}else{
Toast.makeText(v.getContext(), "Login Successfull", Toast.LENGTH_LONG).show();
System.out.println("NAME :"+ui.firstName);
Intent i = new Intent(v.getContext(), MainForm.class);
i.putExtra("uid", ui);
startActivity(i);
finish();
}
}
});
}
public long leftRotateBy(long l, int times) {
return ((l << times) & 0xFFFFFFFFl) | ((l & 0xFFFFFFFFl) >> (32 - times));
}
public int getByteAt(int at) {
if (at < msgLength) {
return (msg[at]);
} else {
at = at - (int) msgLength;
return toPad[at];
}
}
public void padBits(String pass) {
System.out.println("\n\n\n\n");
msg = pass.toCharArray();
msgLength = msg.length;
bitLength = msgLength * 8;
System.out.println("Msg Bit Length: " + bitLength);
System.out.println("MSg Byte Length: " + msgLength);
System.out.println("Required Minimum Bits: " + (bitLength + 65));
long remainder = (bitLength + 65) % 512;
System.out.println("Mod (Bits): " + remainder);
if (remainder == 0) {
requiredBits = 65;
System.out.println("No Padding Needed.");
} else {
requiredBits = (512 - remainder) + 65;
System.out.println(requiredBits + " Bits Padding Needed.");
}
requiredBytes = requiredBits / 8;
toPad = new int[(int) requiredBytes];
System.out.println("Required Bits: " + requiredBits);
System.out.println("Required Bytes: " + requiredBytes);
// manually append 1 to start of pad bits...
toPad[0] = 0x80;
for (int i = 1; i < requiredBytes - 8; i++) {
toPad[i] = 0;
}
long temp = bitLength;
for (int i = (int) (requiredBytes - 1); i >= (int) (requiredBytes - 8); i--) {
int t = (int) (temp & 0xff);
temp = temp >> 8;
toPad[i] = t;
}
System.out.println("TO PAD: ");
for (int i = 0; i < requiredBytes; i++) {
System.out.print(Integer.toHexString(toPad[i]) + " ");
}
System.out.println();
}
public String getSHA1(String pass) {
int kconst[] = new int[]{
0x5A827999,
0x6ED9EBA1,
0x8F1BBCDC,
0xCA62C1D6};
long h0 = 0x67452301;
long h1 = 0xEFCDAB89;
long h2 = 0x98BADCFE;
long h3 = 0x10325476;
long h4 = 0xC3D2E1F0;
long a, b, c, d, e;
padBits(pass);
long totalLength = msgLength + requiredBytes;
System.out.println("TOTAL LENGTH: " + totalLength);
System.out.println("BLOCKS: " + (totalLength / 8));
long w[] = new long[80];
for (int i = 0; i < (int) totalLength; i += 64) {
for (int j = i, kk = 0; j < (i + 64); j += 4, kk++) {
w[kk] = 0xffffffffl & ((getByteAt(j) << 24) | (getByteAt(j + 1) << 16) | (getByteAt(j + 2) << 8) | (getByteAt(j + 3)));
//System.out.println("W[" + kk + "]: " + Long.toHexString(w[kk]));
}
for (int kk = 16; kk < 80; kk++) {
w[kk] = (w[kk - 3] ^ w[kk - 8] ^ w[kk - 14] ^ w[kk - 16]);
w[kk] = leftRotateBy(w[kk], 1);
//System.out.println("W[" + kk + "]: " + Long.toHexString(w[kk]));
}
a = h0;
b = h1;
c = h2;
d = h3;
e = h4;
long temp = 0;
for (int t = 0; t < 20; t++) {
temp = leftRotateBy(a, 5) + ((b & c) | ((~b) & d)) + e + w[t] + kconst[0];
temp &= 0xFFFFFFFFl;
e = d;
d = c;
c = leftRotateBy(b, 30);
b = a;
a = temp;
}
for (int t = 20; t < 40; t++) {
temp = leftRotateBy(a, 5) + (b ^ c ^ d) + e + w[t] + kconst[1];
temp &= 0xFFFFFFFFl;
e = d;
d = c;
c = leftRotateBy(b, 30);
b = a;
a = temp;
}
for (int t = 40; t < 60; t++) {
temp = leftRotateBy(a, 5) + ((b & c) | (b & d) | (c & d)) + e + w[t] + kconst[2];
temp &= 0xFFFFFFFFl;
e = d;
d = c;
c = leftRotateBy(b, 30);
b = a;
a = temp;
}
for (int t = 60; t < 80; t++) {
temp = leftRotateBy(a, 5) + (b ^ c ^ d) + e + w[t] + kconst[3];
temp &= 0xFFFFFFFFl;
e = d;
d = c;
c = leftRotateBy(b, 30);
b = a;
a = temp;
}
h0 = (h0 + a) & 0xFFFFFFFFl;
h1 = (h1 + b) & 0xFFFFFFFFl;
h2 = (h2 + c) & 0xFFFFFFFFl;
h3 = (h3 + d) & 0xFFFFFFFFl;
h4 = (h4 + e) & 0xFFFFFFFFl;
}
return Long.toHexString(h0) + Long.toHexString(h1) + Long.toHexString(h2) + Long.toHexString(h3) + Long.toHexString(h4);
}
Object callService(String INPUT_DATA, String METHOD_NAME, String PARAMETER_NAME){
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
PropertyInfo pi = new PropertyInfo();
pi.setName(PARAMETER_NAME);
pi.setValue(INPUT_DATA);
pi.setType(String.class);
request.addProperty(pi);
envelope.setOutputSoapObject(request);
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
try {
androidHttpTransport.call(SOAP_ACTION, envelope);
SoapObject resultsRequestSOAP = (SoapObject)envelope.bodyIn;
String resp = resultsRequestSOAP.getPrimitivePropertyAsString("return");
return stringToObject(resp);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
Object stringToObject(String inp){
byte b[] = Base64.decode(inp);
Object ret = null;
try {
ByteArrayInputStream bis = new ByteArrayInputStream(b);
ObjectInput in = new ObjectInputStream(bis);
ret = (Object) in.readObject();
bis.close();
in.close();
} catch(Exception e) {
System.out.println("NOT DE-SERIALIZABLE: " + e);
}
return ret;
}
String objectToString(Object obj){
byte[] b = null;
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutput out = new ObjectOutputStream(bos);
out.writeObject(obj);
b = bos.toByteArray();
} catch(Exception e) {
System.out.println("NOT SERIALIZABLE: " + e);
}
return Base64.encode(b);
}
}
/* i have developed an android application which connects to server for login purpose. For connection i have used ksoap2 library. Intracollege webservice is stored on server. The application works fine when connected to server using wifi. if it is not connected to wifi it displays message "application is crashed" and then application stops working.
I only want to display a simple message "Application is not connected to server" if it is not connected to server using wifi.*/
Try this........
public boolean isNet()
{
boolean status=false;
String line;
try
{
URL url = new URL("http://www.google.com");
BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
while(( line = reader.readLine()) != null)
{
}
status=true;
}
catch (IOException ex)
{
System.out.println("ex in isNet : "+ex.toString());
if(ex.toString().equals("java.net.UnknownHostException: www.google.com"))
status=false;
}
catch(Exception e)
{
}
return status;
}
if(status==true)
{
//Do your operation
}
else
show("No Internet Connection.");
When status is true do your login process.Otherwise show message "Application is not connected to server".
To check for the internet connection try this out
private boolean haveNetworkConnection() {
boolean haveConnectedWifi = false;
boolean haveConnectedMobile = false;
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo[] netInfo = cm.getAllNetworkInfo();
for (NetworkInfo ni : netInfo) {
if (ni.getTypeName().equalsIgnoreCase("WIFI"))
if (ni.isConnected())
haveConnectedWifi = true;
if (ni.getTypeName().equalsIgnoreCase("MOBILE"))
if (ni.isConnected())
haveConnectedMobile = true;
}
return haveConnectedWifi || haveConnectedMobile;
}
Check this code, this will help you :
Initialize in the class where you want to check network availability.
OtherUtils otherUtils = new OtherUtils();
if (!otherUtils.isNetworkAvailable(getApplicationContext())) {
Toast.makeText(getApplicationContext(), "No Network Available", Toast.LENGTH_LONG).show();
return;
}
Add below class:
public class OtherUtils{
Context context;
public boolean isNetworkAvailable(Context context) {
this.context = context;
ConnectivityManager connectivity = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivity == null) {
// boitealerte(this.getString(R.string.alertNoNetwork),"getSystemService rend null");
} else {
NetworkInfo[] info = connectivity.getAllNetworkInfo();
if (info != null) {
for (int i = 0; i < info.length; i++) {
if (info[i].getState() == NetworkInfo.State.CONNECTED) {
return true;
}
}
}
}
return false;
}
}
This will surely help you.
We are building an app that is supposed to do several things based on an input text file. First it parses the data in the text file and extracts the useful information and builds a linkedList. The Linked List is a group of BinaryBlock objects. From there we want to dynamically graph the getwfs() function of the BinaryBlocks. At this point, we have got the graph somewhat working but instead of graphing over time it graphs in one big clump and scrolls all the way to the end.
BinaryBlock is listed here:
This is fully tested and functional and really only important in the larger context of the program:
// BinaryBlock.java
public class BinaryBlockLite {
private int pwda[], wfs[];
String lineData;
public BinaryBlockLite( String data ){ // class constructor
lineData = data;
pwda = new int[5];
wfs = new int[4];
setWfs();
}//end constructor
public String WfsToString(){
if (wfs.length == 0)
return "";
String data = "Channel 2: ";
for(int i = 0; i < wfs.length; ++i ){
data = data + "wfs[" + i + "]=" + wfs[i] + " ";
}
return data + "\n";
}
//===========================================================
// Setters
//=============================================================
//read the 5 individual bytes of the Pwda from LineData and into the pwda[] array
private void setPwda(){
int location = 13;
for(int i = 0; i < 5; ++i){
String temp = "" + lineData.charAt(++location) + lineData.charAt(++location);
pwda[i] = Integer.parseInt(temp, 16);
}
}
//logically manipulate the 5 bytes of the PWDA into 4 10-bit WFSs
private void setWfs(){
setPwda();
int j = 0;
for (int i = 0; i < 4; ++i){
wfs[i] = ((pwda[j] << 2) | (( pwda[j + 1] >> 6) & 0x03)) & 0x03ff;
wfs[++i] = ((pwda[j + 1] << 4) | (( pwda[j + 2] >>> 4) & 0x0f)) & 0x03ff;
wfs[++i] = ((pwda[j + 2] << 6) | (( pwda[j + 3] >>> 2) & 0x3f)) & 0x03ff;
wfs[++i] = ((pwda[j + 3] << 8) | (( pwda[j + 4] >>> 0) & 0xff)) & 0x03ff;
}
}
//===========================================================
// Getters
//=============================================================
public int[] getPwda(){
return pwda;
}
public int[] getWfs(){
return wfs;
}
}//end BinaryBlock Class
The main harness is listed here:
The problem is simply that instead of repainting each time and graphing it across the screen, it graphs all of the point at one time.
//MainActivity.java
import android.os.Bundle;
import android.app.ActionBar.LayoutParams;
import android.app.Activity;
import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.Color;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import com.smith.fsu.wave.BinaryBlockLite;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.ListIterator;
import org.achartengine.ChartFactory;
import org.achartengine.GraphicalView;
import org.achartengine.model.XYMultipleSeriesDataset;
import org.achartengine.model.XYSeries;
import org.achartengine.renderer.XYMultipleSeriesRenderer;
import org.achartengine.renderer.XYSeriesRenderer;
public class MainActivity extends Activity {
public static LinkedList<BinaryBlockLite> list;
Button btnMain;
Boolean fileLoaded = false;
int xTick = 0,
lastMinX = 0;
Context context = this;
//
////////////////////////////////////////////////////////////////
//import test
private XYMultipleSeriesDataset WFDataset = new XYMultipleSeriesDataset();
private XYMultipleSeriesRenderer WaveFormRenderer = new XYMultipleSeriesRenderer();
private XYSeries WFCurrentSeries;
private GraphicalView WFChartView;
//////////////////////////////////////////////////////////////////////////
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
list = new LinkedList<BinaryBlockLite>();
btnMain=(Button)findViewById(R.id.btnMain);
WaveFormRenderer.setAxisTitleTextSize(16);
WaveFormRenderer.setChartTitleTextSize(20);
WaveFormRenderer.setLabelsTextSize(15);
WaveFormRenderer.setLegendTextSize(15);
WaveFormRenderer.setMargins(new int[] {20, 30, 15, 0});
WaveFormRenderer.setAxesColor(Color.YELLOW);
String seriesTitle = "Input Data";
XYSeries series = new XYSeries(seriesTitle);
WFDataset.addSeries(series);
WFCurrentSeries = series;
XYSeriesRenderer renderer = new XYSeriesRenderer();
renderer.setColor(Color.GREEN);
WaveFormRenderer.addSeriesRenderer(renderer);
WaveFormRenderer.setXAxisMin(0.0);
WaveFormRenderer.setXAxisMax(500);
// renderer.setFillBelowLine(true) ;
// renderer.setFillBelowLineColor(Color.BLUE);
}
public void chartClick(View view) throws IOException{
String strData = "";
AssetManager amInput = context.getAssets();
BufferedReader reader;
InputStream is = null;
try {
is = amInput.open("Dinamap-Data.txt");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
reader = new BufferedReader(new InputStreamReader(is));
try {
while( (strData = reader.readLine()) != null ) {
addBlock( strData ); //call to paint line
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}//while loop
try {
reader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}//end mainClick() method for btnMain
public void writeClick(View view){
//write decimal data for wfs out to file from LinkedList<BinaryBlock>
//using WfsToString() method of BinaryBlock class in separate thread
(new Thread(new Runnable() {
#Override
public void run() {
FileOutputStream fos = null;
try {
fos = openFileOutput("wfs.txt", Context.MODE_WORLD_READABLE);
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
ListIterator<BinaryBlockLite> itr = list.listIterator();
while (itr.hasNext()){
String temp = itr.next().WfsToString();
try {
fos.write(temp.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
})).start();
btnMain.setEnabled(false);
}
private void addBlock(final String strData) {
new Thread(new Runnable() {
public void run() {
int wfs[];
//read line into binaryBlockLite object and store object in Linked List
BinaryBlockLite bb = new BinaryBlockLite(strData);
list.add(bb);
//get the wfs data from the BinaryBlockLite object
wfs = new int[bb.getWfs().length];
wfs = bb.getWfs();
//grab each wfs individually and paint to the chart, and increment xTick
for (int k = 0; k < wfs.length; ++k){
/* check if we need to shift the x axis */
if (xTick > WaveFormRenderer.getXAxisMax()) {
WaveFormRenderer.setXAxisMax(xTick);
WaveFormRenderer.setXAxisMin(++lastMinX);
}
if (wfs[k] > 1000){
WFCurrentSeries.add(xTick, WFCurrentSeries.getY(xTick - 1));
}
else{
WFCurrentSeries.add(xTick, wfs[k]);
}
++xTick;
}
WFChartView.repaint();
}
}).start();
}
#Override
protected void onResume() {
super.onResume();
if (WFChartView == null) {
LinearLayout layout = (LinearLayout) findViewById(R.id.WFchart);
WFChartView = ChartFactory.getLineChartView(this, WFDataset, WaveFormRenderer);
layout.addView(WFChartView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
// boolean enabled = WFDataset.getSeriesCount() > 0;
// setSeriesEnabled(enabled);
} else {
WFChartView.repaint();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
I think it's either super simple or a threading issue which is something that I haven't played with enough. Any help would be appreciated.
Looking at the code, I see that you add all the data to the series and then call repaint.
If you want the data to be gradually added, then move the repaint inside the for loop and put a Thread.sleep() inside, to give a chance to the UI thread to actually do the repaint.
I am creating a tuner for Android (similar to a guitar tuner) and I am wondering how to allow the tuner to run continuously (for a couple minutes or so). I don't want it to be a service that runs in the background, just while the user is in my app.
I have successfully used the AudioRecord class and am obtaining data that seems correct. I am in the process of filtering this data and finding the fundamental frequency of the input signal, but need help figuring out how to allow my tuner to run continuously.
This is what my code looks like so far:
import android.app.Activity;
import android.graphics.Color;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.dustin.tuner2.FFT;
import com.dustin.tuner2.Complex;
public class Tuner2 extends Activity implements OnClickListener {
Button btnTune;
TextView fft;
TextView freq;
TextView results;
MediaRecorder recorder;
AudioRecord tuner;
boolean startTuning = true;
int audioSource = MediaRecorder.AudioSource.MIC;
int sampleRateInHz = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_SYSTEM);
int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;
int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
int bufferSizeInBytes;
int samples;
short[] audioBuffer;
short[] audioData;
double[] temp;
String fileName;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btnTune = (Button)findViewById(R.id.btnTune);
freq = (TextView)findViewById(R.id.freq);
btnTune.setOnClickListener(this);
bufferSizeInBytes = 4096;
//bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat);
results = (TextView)findViewById(R.id.results);
fft = (TextView)findViewById(R.id.fft);
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (v == btnTune)
{
onTune(startTuning);
if (startTuning) {
((Button)v).setText("Stop Tuning");
}
else {
((Button)v).setText("Start Tuninig");
}
startTuning = !startTuning;
}
}
//------------------------------------------------------------>
private void onTune(boolean start) {
if(start) {
startTuning();
} else {
Toast.makeText(getApplicationContext(), "Tuning Stopped", Toast.LENGTH_SHORT).show();
tuner.stop();
}
}
private void startTuning()
{
tuner = new AudioRecord(audioSource, sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes);
audioData = new short[bufferSizeInBytes];
trigger();
}
public void trigger(){
acquire();
computeFFT();
display();
}
public void acquire(){
try {
tuner.startRecording();
samples = tuner.read(audioData, 0, bufferSizeInBytes);
}
catch (Throwable t){
}
}
public void computeFFT(){
//Conversion from short to double
double[] micBufferData = new double[bufferSizeInBytes];//size may need to change
final int bytesPerSample = 2; // As it is 16bit PCM
final double amplification = 100.0; // choose a number as you like
for (int index = 0, floatIndex = 0; index < bufferSizeInBytes - bytesPerSample + 1; index += bytesPerSample, floatIndex++) {
double sample = 0;
for (int b = 0; b < bytesPerSample; b++) {
int v = audioData[index + b];
if (b < bytesPerSample - 1 || bytesPerSample == 1) {
v &= 0xFF;
}
sample += v << (b * 8);
}
double sample32 = amplification * (sample / 32768.0);
micBufferData[floatIndex] = sample32;
}
//Create Complex array for use in FFT
Complex[] fftTempArray = new Complex[bufferSizeInBytes];
for (int i=0; i<bufferSizeInBytes; i++)
{
fftTempArray[i] = new Complex(micBufferData[i], 0);
}
//Obtain array of FFT data
final Complex[] fftArray = FFT.fft(fftTempArray);
final Complex[] fftInverse = FFT.ifft(fftTempArray);
//Create an array of magnitude of fftArray
double[] magnitude = new double[fftArray.length];
for (int i=0; i<fftArray.length; i++){
magnitude[i]= fftArray[i].abs();
}
fft.setTextColor(Color.GREEN);
fft.setText("fftArray is "+ fftArray[500] +" and fftTempArray is "+fftTempArray[500] + " and fftInverse is "+fftInverse[500]+" and audioData is "+audioData[500]+ " and magnitude is "+ magnitude[1] + ", "+magnitude[500]+", "+magnitude[1000]+" You rock dude!");
for(int i = 2; i < samples; i++){
fft.append(" " + magnitude[i] + " Hz");
}
}
public void display(){
results.setTextColor(Color.BLUE);
results.setText(audioData[1]+"");
for(int i = 2; i < samples; i++){
results.append(" " + audioData[i]);
}
results.invalidate();
//fft.setTextColor(Color.GREEN);
//fft.setText("Buffer size is "+bufferSizeInBytes);
//fft.setText(fftArray[1]+" Hz");
//for(int i = 2; i < samples; i++){
//fft.append(" " + fftArray[i] + " Hz");
//}
//fft.invalidate();
}
Do I need to change something concerning the button and what it does when pressed? Would it just involve the buffer size? How often I compute the FFT?
Unless I am misunderstanding, you could just use a while loop that checks a boolean variable. When the user clicks the stop button set that variable to false.
while (tuning) {
trigger();
}
you should also probably introduce a delay between these calls. It would also be wise to run this code on a thread other than the UI thread. See http://developer.android.com/resources/articles/painless-threading.html
A simple example of what I mean would be to do
new Thread(new Runnable() {
#Override
public void run() {
while (tuning) {
trigger();
try {
Thread.sleep(SLEEP_TIME_MS);
} catch (InterruptedException e) {
// handle exception
}
}
}
}).start();
but then you have to worry about updating the UI as you cannot do that from this Thread. The best option is to use AsyncTask http://developer.android.com/reference/android/os/AsyncTask.html