What i am doing is drawing application and there are two function needed for this project is the undo and redo .. so i need to save a list of previous drawing after each time the user draw and pull up his finger from the screen ..
This is the code when saving previous drawing
public void saveState() {
State mUndoState = new State();
saveState(mSurface.getBitmap(), mUndoState);
}
private void saveState(Bitmap bitmap, State state) {
state.mBuffer = new byte[bitmap.getRowBytes() * bitmap.getHeight()];
Buffer byteBuffer = ByteBuffer.wrap(state.mBuffer);
bitmap.copyPixelsToBuffer(byteBuffer);
mListUndoState.add(state);
System.out.println("Size now: " + (mListUndoState.size() - 1));
mListRedoState.clear();
mListRedoState.add(state);
// StylesFactory.saveState(state.stylesState);
}
private static class State {
byte[] mBuffer = null;
// final HashMap<Integer, Object> stylesState = new HashMap<Integer,
// Object>();
}
The problem is android devices only have 16 MB of heap memory .. what is the best way to deal with this issue? .. i can only save it to ListUndoState 7 to 10 times and then i got out of memory exception .. i want to get unlimited undo action or at least not less then 50 times.
Here is the full class that save the previous drawing for undo and redo.
package com.appshouse.drawgram.utli;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import android.graphics.Bitmap;
public class HistoryHelper {
private final Surface mSurface;
private List<State> mListUndoState = new ArrayList<State>();
private List<State> mListRedoState = new ArrayList<State>();
public HistoryHelper(Surface surface) {
mSurface = surface;
}
public void undo() {
int length = mListUndoState.size() - 1;
if (length <= 0) {
System.out.println("no element is list");
return;
}
System.out.println("history undo size: " + length);
restoreState(mSurface.getBitmap(), mListUndoState.get(length - 1));
mListRedoState.add(mListUndoState.get(length));
mListUndoState.remove(length);
}
public void redo() {
int length = mListRedoState.size() - 1;
if (length <= 0) {
System.out.println("no element is list");
return;
}
System.out.println("history undo size: " + length);
restoreState(mSurface.getBitmap(), mListRedoState.get(length));
mListUndoState.add(mListRedoState.get(length));
mListRedoState.remove(length);
}
private void restoreState(Bitmap bitmap, State state) {
Buffer byteBuffer = ByteBuffer.wrap(state.mBuffer);
bitmap.copyPixelsFromBuffer(byteBuffer);
// StylesFactory.restoreState(state.stylesState);
}
public void saveState() {
State mUndoState = new State();
saveState(mSurface.getBitmap(), mUndoState);
}
private void saveState(Bitmap bitmap, State state) {
state.mBuffer = new byte[bitmap.getRowBytes() * bitmap.getHeight()];
Buffer byteBuffer = ByteBuffer.wrap(state.mBuffer);
bitmap.copyPixelsToBuffer(byteBuffer);
mListUndoState.add(state);
System.out.println("Size now: " + (mListUndoState.size() - 1));
mListRedoState.clear();
mListRedoState.add(state);
// StylesFactory.saveState(state.stylesState);
}
private static class State {
byte[] mBuffer = null;
// final HashMap<Integer, Object> stylesState = new HashMap<Integer,
// Object>();
}
}
As hieuxit suggest i save the bitmap in file-cache to get ride of this problem but i don't know if this is the best solution .. so if anyone got better solution please provide it to me.
Here is what i change in the previous class
package com.appshouse.drawgram.utli;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.widget.Toast;
public class HistoryHelper {
private final Surface mSurface;
int undoAvailable = 0;
int redoAvailable = 0;
Context context;
public HistoryHelper(Context c, Surface surface) {
mSurface = surface;
context = c;
}
public void undo() {
if (undoAvailable > 1) {
undoAvailable--;
new LoadRestoreState().execute();
redoAvailable ++;
} else {
Toast.makeText(context, "End of Undo Data", Toast.LENGTH_LONG)
.show();
}
}
public void redo() {
if(redoAvailable >= 1)
{
undoAvailable ++;
new LoadRestoreState().execute();
redoAvailable --;
}else
{
Toast.makeText(context, "End of Redo Data", Toast.LENGTH_LONG)
.show();
}
}
public void saveState() {
new LoadSaveState().execute(mSurface.getBitmap());
}
private class LoadSaveState extends AsyncTask<Bitmap, Void, Void>
{
#Override
protected Void doInBackground(Bitmap... params) {
undoAvailable++;
FileCache fileCache = new FileCache(context, String.valueOf(undoAvailable));
String str_buffer = Common.getStringDrawing(params[0]);
fileCache.writeFile(str_buffer);
redoAvailable = 0;
return null;
}
}
private class LoadRestoreState extends AsyncTask<Void , Void, Void>
{
#Override
protected Void doInBackground(Void... params) {
FileCache getFileChach = new FileCache(context,
String.valueOf(undoAvailable));
String image_str = getFileChach.readFile();
Bitmap drawing = Common.getBitmapFromString(image_str);
byte[] buffer = new byte[drawing.getRowBytes()
* drawing.getHeight()];
Buffer byteBuffer = ByteBuffer.wrap(buffer);
drawing.copyPixelsToBuffer(byteBuffer);
byteBuffer = ByteBuffer.wrap(buffer);
mSurface.getBitmap().copyPixelsFromBuffer(byteBuffer);
return null;
}
}
}
Where the FileCache class is:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import android.content.Context;
public class FileCache {
private File cacheDir;
private File TempFile;
public FileCache(Context context, String Filename) {
cacheDir = context.getCacheDir();
if (!cacheDir.exists())
cacheDir.mkdirs();
TempFile = new File(cacheDir.getPath(), Filename);
}
public void writeFile(String buffer)
{
FileWriter writer = null;
try {
writer = new FileWriter(TempFile);
writer.write(buffer);
System.out.println(TempFile + " File - data: " + buffer.toString()
);
writer.close();
} catch (IOException e) {
}
}
public String readFile() {
String strLine = "";
StringBuilder text = new StringBuilder();
try {
FileReader fileReader = new FileReader(TempFile);
BufferedReader bufferReader = new BufferedReader(fileReader);
while ((strLine = bufferReader.readLine()) != null) {
text.append(strLine + "\n");
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("get text String: "+text.toString());
return text.toString();
}
public void clear() {
File[] files = cacheDir.listFiles();
if (files == null)
return;
for (File f : files)
f.delete();
}
}
And Here is Two Function that i created in Common class:
public static String getStringDrawing(Bitmap bm) {
String image_str = "";
ByteArrayOutputStream stream = new ByteArrayOutputStream();
byte[] byte_arr;
bm.compress(Bitmap.CompressFormat.PNG, 90, stream);
byte_arr = stream.toByteArray();
image_str = Base64.encodeBytes(byte_arr);
return image_str;
}
public static Bitmap getBitmapFromString(String img_str)
{
Bitmap bmImg = null;
try {
byte[] encodeByte = null;
encodeByte = Base64.decode(img_str);
bmImg = BitmapFactory.decodeByteArray(encodeByte, 0,
encodeByte.length);
bmImg = Bitmap.createBitmap(bmImg);
} catch (Exception e) {
e.printStackTrace();
}
return bmImg;
}
of-course you need to download base64 class for converting the image to string and vice versa
Related
i am using sugar orm to store my data in sqlite database in android and it is working perfectly so now i want to store the data in the local storage rather than the default path so how can i achieve that and moreover that is it possible to do this
Thanks.
This is my mainactivity code
public class MainActivity extends AppCompatActivity {
EditText firstname;
EditText lastname;
Button button;
Note note;
public SQLiteDatabase database;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
firstname=findViewById(R.id.edit1);
lastname=findViewById(R.id.edit2);
button=findViewById(R.id.button);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
return id == R.id.action_settings || super.onOptionsItemSelected(item);
}
public void click(View view) {
String first = firstname.getText().toString();
String last = lastname.getText().toString();
note = new Note(first, last);
note.save();
if (note.getFirstname() != null && note.getLastname() != null) {
firstname.setText("");
lastname.setText("");
}
onShareDb();
//Log.e("Notes saved", String.valueOf(onShareDb()));
}
public void show(View view) {
String one=note.getFirstname();
String two=note.getLastname();
Log.e("firstName",one);
Log.e("lastName",two);
}
public void update(View view) {
note = Note.findById(Note.class, 4);
Log.e("firstName",note.getFirstname());
note.setFirstname("kullu");
Log.e("firstName",note.getFirstname());
note.save();
}
public void delete(View view) {
note = Note.findById(Note.class, 2);
if(note.getId()==null){
Toast.makeText(this,"there is no such data",Toast.LENGTH_SHORT).show();
}
Log.e("firstName",note.getFirstname());
note.delete();
Log.e("firstName",note.getFirstname());
}
public void onShareDb() {
#SuppressLint("SimpleDateFormat") SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
String output_name = "YourApp_" + df.format(new Date()) + ".db";
File output_file = new File(getExternalCacheDir() + File.separator + output_name);
try {
File file = new File(new SugarDb(MainActivity.this).getDB().getPath()); // get private db reference
if (!file.exists() || file.length() == 0) throw new Exception("Empty DB");
//IOUtils.copy(new FileInputStream(file), new FileOutputStream(output_file));
/* Intent i = new Intent(Intent.ACTION_SEND);
i.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(output_file));
startActivity(Intent.createChooser(i, "Send db"));*/
database = SQLiteDatabase.openDatabase(output_file
+ File.separator + "notes.db", null,
SQLiteDatabase.OPEN_READWRITE);
Log.e("storage", String.valueOf(database));
} catch (Exception e) {
Toast.makeText(getApplicationContext(), "Unable to export db: " + e.getMessage(), Toast.LENGTH_SHORT).show();
Log.e("storage", e.getMessage());
}
}
}
So, basically i m trying to get the path of stored images by using the shareDB() property of sugar orm and trying to overwrite the default path to my new path so how do i get it done, i m calling shareDB method in button click listener, the exception is something like unknown error: could not open database.
After a lot of research and trial error, I somehow manage to succeed in copying the sqllite file from one folder to another folder in the directory
Here is the code,
private void copyDatabase() throws IOException {
File actualFile = new File(new SugarDb(MainActivity.this).getDB().getPath());
File cuurentfile = new File(actualFile.toString());
Log.e("actualPath", actualFile.toString());
File newFile = createTempFile("sugarFiles",".db",Environment.getExternalStorageDirectory());
Log.e("newPath", newFile.toString());
boolean yes=FileUtils.copyFile(cuurentfile,newFile);
if(yes) {
Log.e("result", "" + true);
}
}
call this copydatabase function inside the click listener or wherever you are inserting into the database, make sure it is after you set the insertion values, in my case
public void click(View view) {
String first = firstname.getText().toString();
String last = lastname.getText().toString();
note = new Note(first, last);
note.save();
if (note.getFirstname() != null && note.getLastname() != null) {
firstname.setText("");
lastname.setText("");
}
try {
copyDatabase();
} catch (IOException e) {
e.printStackTrace();
}
}
FileUtils.java
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
public class FileUtils {
FileUtils instance = null;
public FileUtils getInstance() {
instance = new FileUtils();
return instance;
}
public static Boolean copyFile(File sourceFile, File destFile)
throws IOException {
// if (!destFile.exists()) {
destFile.createNewFile();
FileChannel source = null;
FileChannel destination = null;
try {
source = new FileInputStream(sourceFile).getChannel();
destination = new FileOutputStream(destFile).getChannel();
destination.transferFrom(source, 0, source.size());
} finally {
if (source != null)
source.close();
if (destination != null)
destination.close();
}
return true;
// }
// return false;
}
/**
* Read a text file into a String.
*
* #param file
* File to read (will not seek, so things like /proc files are
* OK).
* #return The contents of the file as a String.
* #throws IOException
*/
public static String readTextFile(File file) throws IOException {
byte[] buffer = new byte[(int) file.length()];
BufferedInputStream stream = new BufferedInputStream(
new FileInputStream(file));
stream.read(buffer);
stream.close();
return new String(buffer);
}
}
Hope it helps someone someday...Have a nice day
I want convert mp4 video to mp3 audio file in Android platform?
How can I do it?
Actually I test some JAR.
Firstly, the JAAD lib be used to test.
import java.io.File;
import java.io.RandomAccessFile;
import java.util.List;
import net.sourceforge.jaad.aac.Decoder;
import net.sourceforge.jaad.aac.SampleBuffer;
import net.sourceforge.jaad.mp4.MP4Container;
import net.sourceforge.jaad.mp4.api.AudioTrack;
import net.sourceforge.jaad.mp4.api.Frame;
import net.sourceforge.jaad.mp4.api.Movie;
import net.sourceforge.jaad.mp4.api.Track;
import net.sourceforge.jaad.util.wav.WaveFileWriter;
public class Main2 {
public static void main(String[] args) {
System.out.println("dfd");
try {
decodeMP4("C:/a/input.mp4","./out.wav");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("over");
}
private static void decodeMP4(String in, String out) throws Exception {
WaveFileWriter wav = null;
try {
final MP4Container cont = new MP4Container(new RandomAccessFile(in, "r"));
final Movie movie = cont.getMovie();
final List<Track> tracks = movie.getTracks(AudioTrack.AudioCodec.AAC);
if(tracks.isEmpty()) throw new Exception("movie does not contain any AAC track");
final AudioTrack track = (AudioTrack) tracks.get(0);
wav = new WaveFileWriter(new File(out), track.getSampleRate(), track.getChannelCount(), track.getSampleSize());
final Decoder dec = new Decoder(track.getDecoderSpecificInfo());
Frame frame;
final SampleBuffer buf = new SampleBuffer();
while(track.hasMoreFrames()) {
frame = track.readNextFrame();
dec.decodeFrame(frame.getData(), buf);
wav.write(buf.getData());
}
}
finally {
if(wav!=null) wav.close();
}
}
}
but it throws an error
"java.lang.ClassCastException: net.sourceforge.jaad.mp4.boxes.impl.PixelAspectRatioBox cannot be cast to net.sourceforge.jaad.mp4.boxes.impl.sampleentries.codec.CodecSpecificBox
at net.sourceforge.jaad.mp4.api.VideoTrack.<init>(VideoTrack.java:62)
at net.sourceforge.jaad.mp4.api.Movie.createTrack(Movie.java:65)
at net.sourceforge.jaad.mp4.api.Movie.<init>(Movie.java:46)
at net.sourceforge.jaad.mp4.MP4Container.getMovie(MP4Container.java:134)
at Main2.decodeMP4(Main2.java:30)
at Main2.main(Main2.java:18)"
This question is a little too complex. I know how to implement it.
here is the code to extract audio data from video file ,but it's PCM data ,not mp3:
public class AudioFromVideo{
private String audio,video;
private MediaCodec amc;
private MediaExtractor ame;
private MediaFormat amf;
private String amime;
public AudioFromVideo(String srcVideo,String destAudio){
this.audio=destAudio;
this.video=srcVideo;
ame=new MediaExtractor();
init();
}
public void init(){
try {
ame.setDataSource(video);
amf=ame.getTrackFormat(1);
ame.selectTrack(1);
amime=amf.getString(MediaFormat.KEY_MIME);
amc=MediaCodec.createDecoderByType(amime);
amc.configure(amf, null, null, 0);
amc.start();
} catch (IOException e) {
e.printStackTrace();
}
}
public void start(){
new AudioService(amc,ame,audio).start();
}
private class AudioService extends Thread{
private MediaCodec amc;
private MediaExtractor ame;
private ByteBuffer[] aInputBuffers,aOutputBuffers;
private String destFile;
#SuppressWarnings("deprecation")
AudioService(MediaCodec amc,MediaExtractor ame,String destFile){
this.amc=amc;
this.ame=ame;
this.destFile=destFile;
aInputBuffers=amc.getInputBuffers();
aOutputBuffers=amc.getOutputBuffers();
}
#SuppressWarnings("deprecation")
public void run(){
try {
OutputStream os=new FileOutputStream(new File(destFile));
long count=0;
while(true){
int inputIndex=amc.dequeueInputBuffer(0);
if(inputIndex==-1){
continue;
}
int sampleSize=ame.readSampleData(aInputBuffers[inputIndex], 0);
if(sampleSize==-1)break;
long presentationTime=ame.getSampleTime();
int flag=ame.getSampleFlags();
ame.advance();
amc.queueInputBuffer(inputIndex, 0, sampleSize, presentationTime, flag);
BufferInfo info=new BufferInfo();
int outputIndex=amc.dequeueOutputBuffer(info, 0);
if (outputIndex >= 0) {
byte[] data=new byte[info.size];
aOutputBuffers[outputIndex].get(data, 0, data.length);
aOutputBuffers[outputIndex].clear();
os.write(data);
count+=data.length;
Log.i("write", ""+count);
amc.releaseOutputBuffer(outputIndex, false);
} else if (outputIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
aOutputBuffers = amc.getOutputBuffers();
} else if (outputIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {}
}
os.flush();
os.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
For example ,to extract audio data from Video file video.mp4,and save the extracted date into file audio.pcm,write code like this:
String videoPath=PATH+"/video.mp4";
String audioPath=PATH+"/audio.pcm";
new AudioFromVideo(video.audio).start();
If you need mp3 data,you can use lame mp3 lib to encode PCM data to MP3 format.I have all the code. but it is not convinent to paste all of them here.
I have 231 sound files ( duration ~ 0.2 Sec each) of size 5.7 MB total to load into my android project. I am trying load them when the application starts using for loop like
for (int i = 0; i < 231; i++){
...
loadSoundAsset(i); //method to load the sound files
i++;
...
}
Yet the above method is taking too long to load the sound files. What should be done to load effectively many asset files into android project?
I create sample code for you. How to get faster? (I test it for assets files about 180 sounds files.)
MainActivity
public class MainActivity extends Activity implements TaskListener {
MultiLoader loader = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView view = new TextView(this);
view.setText("Loader");
setContentView(view);
}
#Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
loader = new MultiLoader(this, this);
loader.load("sound");
}
#Override
public void onTaskEnd() {
Vector<byte[]> soundDatas = loader.getData();
Log.e("MainActivity", "TaskEnd");
}
#Override
protected void onDestroy() {
loader.clear();
super.onDestroy();
}
}
MultiLoader
package com.fastload;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Vector;
import java.util.regex.Pattern;
import android.content.Context;
import android.util.Log;
public class MultiLoader {
private int threadCount = 0;
private String[] mFiles;
private Vector<byte[]> fileContents = new Vector<byte[]>();
private Thread[] mQueue = null;
private Context mContext;
private TaskListener listener;
public MultiLoader(Context mContext, TaskListener listener) {
super();
this.mContext = mContext;
this.listener = listener;
}
public Vector<byte[]> getData(){
return fileContents;
}
public void reQueue(int index){
boolean status = true;
mQueue[index] = null;
for(Thread item : mQueue){
status &= (item == null);
}
if(status){
listener.onTaskEnd();
}
}
public void load(final String path){
initialize(path);
if(mFiles == null || (mFiles != null && mFiles.length < 1))
return;
mQueue = new Thread[threadCount];
for(int i = 0; i < threadCount; ++i){
int len = mFiles.length;
int piece = len / threadCount;
final int startIndex = i * piece;
final int endIndex = (i == threadCount - 1) ? len - startIndex - 1 : startIndex + piece;
MyTask task = new MyTask("MyTask##"+i, i, new EndListener(){
#Override
public void onEnd(int index, String name) {
Log.e("ThreadEND", "name = "+name);
reQueue(index);
}
}) {
#Override
public void execute() {
for(int index = startIndex; index < endIndex; ++index){
File file = new File(mFiles[index]);
InputStream is = null;
ByteArrayOutputStream os = null;
byte[] data = null;
try {
is = mContext.getAssets().open(path + File.separator + file.getName());
os = new ByteArrayOutputStream();
int count = 0;
byte[] buffer = new byte[1024];
while((count = is.read(buffer)) > 0){
os.write(buffer, 0, count);
}
os.flush();
data = os.toByteArray();
debug(getName(), index, path + File.separator + file.getName());
} catch (Exception e) {
e.printStackTrace();
} finally{
if(is != null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(os != null){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
if(data != null){
add(data);
}
}
}
};
mQueue[i] = task;
task.start();
}
}
private void debug(String who, int index, String name){
Log.e("MULTI LOADER DEBUG", "who = "+who+" , name = "+name+", index = "+index);
}
private void initialize(String path){
threadCount = getNumCores() * 2;
try {
mFiles = mContext.getAssets().list(path);
} catch (IOException e) {
e.printStackTrace();
}
}
private void add(byte[] data){
synchronized (fileContents) {
fileContents.add(data);
}
}
private void remove(byte[] data){
synchronized (fileContents) {
fileContents.remove(data);
}
}
public void clear(){
synchronized (fileContents) {
fileContents.clear();
}
}
private int getNumCores() {
class CpuFilter implements FileFilter {
#Override
public boolean accept(File pathname) {
if(Pattern.matches("cpu[0-9]+", pathname.getName())) {
return true;
}
return false;
}
}
try {
File dir = new File("/sys/devices/system/cpu/");
File[] files = dir.listFiles(new CpuFilter());
return files.length;
} catch(Exception e) {
return 1;
}
}
private abstract class MyTask extends Thread{
private EndListener listener;
private int index;
private MyTask() { }
public MyTask(String threadName, int index, EndListener listener) {
super(threadName);
this.index = index;
this.listener = listener;
}
public abstract void execute();
#Override
public void run() {
execute();
end();
}
public void end(){
listener.onEnd(index, getName());
}
public int getIndex(){
return index;
}
}
public interface TaskListener{
public void onTaskEnd();
}
public interface EndListener{
public void onEnd(int index, String name);
}
}
I'm using the ARexampleLocationBased tutorial ,the POIS ar correctly shown but the annottations are not shown ,,the program works correct but the billoboards image down the POI's are not visible
package pfg.proyecto.com.proyecto;
import android.view.View;
import com.metaio.sdk.ARELActivity;
public class ARELViewActivity extends ARELActivity
{
#Override
protected int getGUILayout()
{
return R.layout.activity_main;
}
public void onButtonClick(View v)
{
finish();
}
}
and this is the main activity code
package pfg.proyecto.com.proyecto;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.TextPaint;
import android.util.Log;
import android.view.View;
import com.metaio.cloud.plugin.util.MetaioCloudUtils;
import com.metaio.sdk.ARELInterpreterAndroidJava;
import com.metaio.sdk.ARViewActivity;
import com.metaio.sdk.MetaioDebug;
import com.metaio.sdk.jni.AnnotatedGeometriesGroupCallback;
import com.metaio.sdk.jni.EGEOMETRY_FOCUS_STATE;
import com.metaio.sdk.jni.IAnnotatedGeometriesGroup;
import com.metaio.sdk.jni.IGeometry;
import com.metaio.sdk.jni.IMetaioSDKCallback;
import com.metaio.sdk.jni.IRadar;
import com.metaio.sdk.jni.ImageStruct;
import com.metaio.sdk.jni.LLACoordinate;
import com.metaio.sdk.jni.Rotation;
import com.metaio.sdk.jni.SensorValues;
import com.metaio.sdk.jni.Vector3d;
import com.metaio.tools.io.AssetsManager;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.locks.Lock;
public class MainActivity extends ARViewActivity
{
private IAnnotatedGeometriesGroup mAnnotatedGeometriesGroup;
private MyAnnotatedGeometriesGroupCallback mAnnotatedGeometriesGroupCallback;
/**
* Geometries
*/
private IGeometry mLondonGeo;
private IGeometry mMunichGeo;
private IGeometry mRomeGeo;
private IGeometry mTokyoGeo;
private IGeometry mParisGeo;
private IRadar mRadar;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Set GPS tracking configuration
boolean result = metaioSDK.setTrackingConfiguration("GPS", false);
new LoadAssets().execute(0);
MetaioDebug.log("Tracking data loaded: " + result);
}
#Override
protected void onDestroy()
{
// Break circular reference of Java objects
if (mAnnotatedGeometriesGroup != null)
{
mAnnotatedGeometriesGroup.registerCallback(null);
}
if (mAnnotatedGeometriesGroupCallback != null)
{
mAnnotatedGeometriesGroupCallback.delete();
mAnnotatedGeometriesGroupCallback = null;
}
super.onDestroy();
}
#Override
public void onDrawFrame()
{
if (metaioSDK != null && mSensors != null)
{
SensorValues sensorValues = mSensors.getSensorValues();
float heading = 0.0f;
if (sensorValues.hasAttitude())
{
float m[] = new float[9];
sensorValues.getAttitude().getRotationMatrix(m);
Vector3d v = new Vector3d(m[6], m[7], m[8]);
v.normalize();
heading = (float)(-Math.atan2(v.getY(), v.getX()) - Math.PI / 2.0);
}
IGeometry geos[] = new IGeometry[] {mLondonGeo, mParisGeo, mRomeGeo, mTokyoGeo,};
Rotation rot = new Rotation((float)(Math.PI / 2.0), 0.0f, -heading);
for (IGeometry geo : geos)
{
if (geo != null)
{
geo.setRotation(rot);
}
}
}
super.onDrawFrame();
}
public void onButtonClick(View v)
{
finish();
}
#Override
protected int getGUILayout()
{
return R.layout.activity_main;
}
#Override
protected IMetaioSDKCallback getMetaioSDKCallbackHandler()
{
return null;
}
#Override
protected void loadContents()
{
mAnnotatedGeometriesGroup = metaioSDK.createAnnotatedGeometriesGroup();
mAnnotatedGeometriesGroupCallback = new MyAnnotatedGeometriesGroupCallback();
mAnnotatedGeometriesGroup.registerCallback(mAnnotatedGeometriesGroupCallback);
// Clamp geometries' Z position to range [5000;200000] no matter how close or far they are
// away.
// This influences minimum and maximum scaling of the geometries (easier for development).
metaioSDK.setLLAObjectRenderingLimits(5, 200);
// Set render frustum accordingly
metaioSDK.setRendererClippingPlaneLimits(10, 220000);
// let's create LLA objects for known cities
LLACoordinate munich = new LLACoordinate(48.142573, 11.550321, 0, 0);
LLACoordinate london = new LLACoordinate(51.50661, -0.130463, 0, 0);
LLACoordinate tokyo = new LLACoordinate(35.657464, 139.773865, 0, 0);
LLACoordinate rome = new LLACoordinate(41.90177, 12.45987, 0, 0);
LLACoordinate paris = new LLACoordinate(48.85658, 2.348671, 0, 0);
LLACoordinate parque = new LLACoordinate(36.465985, -6.201081, 0, 0);
// Load some POIs. Each of them has the same shape at its geoposition. We pass a string
// (const char*) to IAnnotatedGeometriesGroup::addGeometry so that we can use it as POI
// title
// in the callback, in order to create an annotation image with the title on it.
mLondonGeo = createPOIGeometry(london);
mAnnotatedGeometriesGroup.addGeometry(mLondonGeo, "London");
mParisGeo = createPOIGeometry(paris);
mAnnotatedGeometriesGroup.addGeometry(mParisGeo, "Paris");
mRomeGeo = createPOIGeometry(rome);
mAnnotatedGeometriesGroup.addGeometry(mRomeGeo, "Rome");
mTokyoGeo = createPOIGeometry(tokyo);
mAnnotatedGeometriesGroup.addGeometry(mTokyoGeo, "Tokyo");
File metaioManModel =
AssetsManager.getAssetPathAsFile(getApplicationContext(),
"metaioman.md2");
if (metaioManModel != null)
{
mMunichGeo = metaioSDK.createGeometry(metaioManModel);
if (mMunichGeo != null)
{
mMunichGeo.setTranslationLLA(munich);
mMunichGeo.setLLALimitsEnabled(true);
mMunichGeo.setScale(500);
}
else
{
MetaioDebug.log(Log.ERROR, "Error loading geometry: " + metaioManModel);
}
}
// create radar
mRadar = metaioSDK.createRadar();
mRadar.setBackgroundTexture(AssetsManager.getAssetPathAsFile(getApplicationContext(),
"radar.png"));
mRadar.setObjectsDefaultTexture(AssetsManager.getAssetPathAsFile(getApplicationContext(),
"yellow.png"));
mRadar.setRelativeToScreen(IGeometry.ANCHOR_TL);
// add geometries to the radar
mRadar.add(mLondonGeo);
mRadar.add(mMunichGeo);
mRadar.add(mTokyoGeo);
mRadar.add(mParisGeo);
mRadar.add(mRomeGeo);
}
private IGeometry createPOIGeometry(LLACoordinate lla)
{
final File path =
AssetsManager.getAssetPathAsFile(getApplicationContext(),
"ExamplePOI.obj");
if (path != null)
{
IGeometry geo = metaioSDK.createGeometry(path);
geo.setTranslationLLA(lla);
geo.setLLALimitsEnabled(true);
geo.setScale(100);
return geo;
}
else
{
MetaioDebug.log(Log.ERROR, "Missing files for POI geometry");
return null;
}
}
#Override
protected void onGeometryTouched(final IGeometry geometry)
{
MetaioDebug.log("Geometry selected: " + geometry);
mSurfaceView.queueEvent(new Runnable()
{
#Override
public void run()
{
mRadar.setObjectsDefaultTexture(AssetsManager.getAssetPathAsFile(getApplicationContext(),
"yellow.png"));
mRadar.setObjectTexture(geometry, AssetsManager.getAssetPathAsFile(getApplicationContext(),
"red.png"));
mAnnotatedGeometriesGroup.setSelectedGeometry(geometry);
}
});
}
final class MyAnnotatedGeometriesGroupCallback extends AnnotatedGeometriesGroupCallback
{
Bitmap mAnnotationBackground, mEmptyStarImage, mFullStarImage;
int mAnnotationBackgroundIndex;
ImageStruct texture;
String[] textureHash = new String[1];
TextPaint mPaint;
Lock geometryLock;
Bitmap inOutCachedBitmaps[] = new Bitmap[] {mAnnotationBackground, mEmptyStarImage, mFullStarImage};
int inOutCachedAnnotationBackgroundIndex[] = new int[] {mAnnotationBackgroundIndex};
public MyAnnotatedGeometriesGroupCallback()
{
mPaint = new TextPaint();
mPaint.setFilterBitmap(true); // enable dithering
mPaint.setAntiAlias(true); // enable anti-aliasing
}
#Override
public IGeometry loadUpdatedAnnotation(IGeometry geometry, Object userData, IGeometry existingAnnotation)
{
if (userData == null)
{
return null;
}
if (existingAnnotation != null)
{
// We don't update the annotation if e.g. distance has changed
return existingAnnotation;
}
String title = (String)userData; // as passed to addGeometry
LLACoordinate location = geometry.getTranslationLLA();
float distance = (float)MetaioCloudUtils.getDistanceBetweenTwoCoordinates(location, mSensors.getLocation());
Bitmap thumbnail = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
try
{
texture =
ARELInterpreterAndroidJava.getAnnotationImageForPOI(title, title, distance, "5", thumbnail,
null,
metaioSDK.getRenderSize(), MainActivity.this,
mPaint, inOutCachedBitmaps, inOutCachedAnnotationBackgroundIndex, textureHash);
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
if (thumbnail != null)
thumbnail.recycle();
thumbnail = null;
}
mAnnotationBackground = inOutCachedBitmaps[0];
mEmptyStarImage = inOutCachedBitmaps[1];
mFullStarImage = inOutCachedBitmaps[2];
mAnnotationBackgroundIndex = inOutCachedAnnotationBackgroundIndex[0];
IGeometry resultGeometry = null;
if (texture != null)
{
if (geometryLock != null)
{
geometryLock.lock();
}
try
{
// Use texture "hash" to ensure that SDK loads new texture if texture changed
resultGeometry = metaioSDK.createGeometryFromImage(textureHash[0], texture, true, false);
}
finally
{
if (geometryLock != null)
{
geometryLock.unlock();
}
}
}
return resultGeometry;
}
#Override
public void onFocusStateChanged(IGeometry geometry, Object userData, EGEOMETRY_FOCUS_STATE oldState,
EGEOMETRY_FOCUS_STATE newState)
{
MetaioDebug.log("onFocusStateChanged for " + (String)userData + ", " + oldState + "->" + newState);
}
}
public class LoadAssets extends AsyncTask<Integer, Integer, Boolean> {
#Override
protected Boolean doInBackground(Integer... params) {
try
{
// Extract all assets and overwrite existing files if debug build
AssetsManager.extractAllAssets(getApplicationContext(), BuildConfig.DEBUG);
}
catch (IOException e)
{
MetaioDebug.log(Log.ERROR, "Error extracting assets: " + e.getMessage());
MetaioDebug.printStackTrace(Log.ERROR, e);
return false;
}
return true;
}
}
}
Somebody knows what is wrong?
if you use skd 5.3 or later you must copy assets/junaio folder of tutorial(example_SDK) into your assets folder so your poi shown.
i've just found it i am working on that right know. my poi.obj rotates...
I am new to OSM and OSMdroid.
I was following this pretty good tutorial to show offline maps. So basically what I have done is:
Created a tile package in zip format with Mobile Atlas Creator
Used MapQuest source, JPEG format
Put the zip into the right folder: /mnt/sdcard/osmdroid/
The problem was the tiles were not rendered. I got a blank page.
I found this solution, to solve my problem.
But now, it is bothering me that I have to use PNG files, that takes significantly more space. It is not really efficient for my app because the user will have to download a much larger package.
MY QUESTION IS: How can I use JPEG tiles with OSMDroid and MapQuest?
Thanks in advance.
This works to get JPGs instead of PNGs:
MapView myOpenMapView;
myOpenMapView = (MapView) findViewById(R.id.openmapview);
myOpenMapView.setTileSource(new XYTileSource("MapquestOSM", ResourceProxy.string.mapquest_osm, 0, 18, 256, ".jpg", new String[] {
"http://otile1.mqcdn.com/tiles/1.0.0/map/", "http://otile2.mqcdn.com/tiles/1.0.0/map/", "http://otile3.mqcdn.com/tiles/1.0.0/map/",
"http://otile4.mqcdn.com/tiles/1.0.0/map/" }));
Notice ".jpg" in line 3.
I created a tile source that suppoort jpg, you can take a look and adapt your case,
Please note that getTileRelativeFilenameString won't contain .title ext. That part will be added by (MapTileFilesystemProvider)
import java.io.File;
import java.io.InputStream;
import java.util.Random;
import org.osmdroid.ResourceProxy;
import org.osmdroid.ResourceProxy.string;
import org.osmdroid.tileprovider.MapTile;
import org.osmdroid.tileprovider.tilesource.BitmapTileSourceBase.LowMemoryException;
import org.osmdroid.tileprovider.tilesource.ITileSource;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
public class MapTilerCustomDataSource implements ITileSource {
private static int globalOrdinal = 0;
private final int mMinimumZoomLevel;
private final int mMaximumZoomLevel;
private final int mOrdinal;
protected final String mName;
protected final String mImageFilenameEnding;
protected final Random random = new Random();
private final int mTileSizePixels;
private final string mResourceId;
public MapTilerCustomDataSource() {
mResourceId = null;
mOrdinal = globalOrdinal++;
mName = "MapquestOSM";
mMinimumZoomLevel = 0;
mMaximumZoomLevel = 20;
mTileSizePixels = 256;
mImageFilenameEnding = ".jpg";
}
#Override
public String getTileRelativeFilenameString(final MapTile tile) {
final StringBuilder sb = new StringBuilder();
sb.append(pathBase());
sb.append('/');
sb.append(tile.getZoomLevel());
sb.append('/');
sb.append(tile.getX());
sb.append('/');
sb.append(tile.getY());
sb.append(imageFilenameEnding());
return sb.toString();
}
#Override
public Drawable getDrawable(String aFilePath) throws LowMemoryException {
try {
// default implementation will load the file as a bitmap and create
// a BitmapDrawable from it
final Bitmap bitmap = BitmapFactory.decodeFile(aFilePath);
if (bitmap != null) {
return new BitmapDrawable(bitmap);
} else {
// if we couldn't load it then it's invalid - delete it
try {
new File(aFilePath).delete();
} catch (final Throwable e) {
}
}
} catch (final OutOfMemoryError e) {
System.gc();
}
return null;
}
#Override
public Drawable getDrawable(InputStream aFileInputStream) throws LowMemoryException {
try {
// default implementation will load the file as a bitmap and create
// a BitmapDrawable from it
final Bitmap bitmap = BitmapFactory.decodeStream(aFileInputStream);
if (bitmap != null) {
return new BitmapDrawable(bitmap);
}
} catch (final OutOfMemoryError e) {
System.gc();
}
return null;
}
#Override
public int ordinal() {
return mOrdinal;
}
#Override
public String name() {
return mName;
}
public String pathBase() {
return mName;
}
public String imageFilenameEnding() {
return mImageFilenameEnding;
}
#Override
public int getMinimumZoomLevel() {
return mMinimumZoomLevel;
}
#Override
public int getMaximumZoomLevel() {
return mMaximumZoomLevel;
}
#Override
public int getTileSizePixels() {
return mTileSizePixels;
}
#Override
public String localizedName(final ResourceProxy proxy) {
return proxy.getString(mResourceId);
}
}
Download 'xxx.JPG.tile' files and rename them to 'xxx.PNG.tile'.