I have developed an application that uses the Android's Dream Service as a screen saver of sorts - it displays a slideshow of images. These images are housed in binary format within a database and decoded. I realize this is not the best way, but given the particular structure and purpose of this application, it is the most realistic. Additionally, the class does not make constant trips to database nor continuously decode image - it does this when it starts and then closes the resources.
With that being said, after the screen saver has run for a while, I occasionally receive an "Application has Stopped Working" message which I believe is related to an out of memory error. I find this a little odd because, far as I am aware, the bitmaps are only decoded once - when the service is attached to window. I do not see why there would be issues with memory when the only repetitive action is loading a bitmap into an ImageView container, certainly not something I believe requires a great deal of resources. I have looked over my code and have been unable to locate the issue.
What am I doing wrong; how can I stop these errors from occurring?
public class screenSaver extends DreamService {
XmlPullParser parser;
String storeImages = "";
// creates messages
public Bitmap drawText(Context c, int resource, String text) {
Resources resources = c.getResources();
Bitmap bitmap = BitmapFactory.decodeResource(resources, resource);
android.graphics.Bitmap.Config config = bitmap.getConfig();
if (config == null) {
config = android.graphics.Bitmap.Config.ARGB_8888;
}
bitmap = bitmap.copy(config, true);
Canvas canvas = new Canvas(bitmap);
TextPaint paint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
float scale = resources.getDisplayMetrics().density;
paint.setColor(Color.BLACK);
paint.setTextSize(48 * scale);
int textWidth = canvas.getWidth() - (int) (16 * scale);
StaticLayout textLayout = new StaticLayout(text, paint, textWidth, Layout.Alignment.ALIGN_CENTER, 1f, 0f, false);
int textHeight = textLayout.getHeight();
float x = (bitmap.getWidth() - textWidth) / 2;
float y = (bitmap.getHeight() - textHeight) / 2;
canvas.save();
canvas.translate(x, y);
textLayout.draw(canvas);
canvas.restore();
return bitmap;
}
ArrayList<Bitmap> imageList = new ArrayList<Bitmap>();
int slideCounter = 0;
ImageView slide;
Cursor images;
Cursor corpImages;
final Handler handler = new Handler(Looper.getMainLooper());
private int counter = 0;
private Runnable runnable = new Runnable() {
#Override
public void run() {
slide.setImageBitmap(imageList.get(counter));
if (counter == (imageList.size() - 1)) {
counter = 0;
} else {
counter++;
}
}
};
public screenSaver() {
}
#Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
setInteractive(false);
setFullscreen(true);
setContentView(R.layout.screen_saver);
databaseHelper dbHelper = new databaseHelper(this);
Intent testIntent = new Intent(this, lockActivity.class);
testIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
this.startActivity(testIntent); // unpin screen so screen saver can load
SQLiteDatabase db = dbHelper.getReadableDatabase();
SharedPreferences preferences = getSharedPreferences("config", MODE_PRIVATE);
final String store = preferences.getString("store", "");
String managerMessageText = "";
String mainMessageText = "";
String districtMessageText = "";
try {
FileInputStream input = new FileInputStream(new File(this.getFilesDir(), "stores.xml"));
parser = Xml.newPullParser();
parser.setInput(input, null);
// begin search for correct 'store' tag
boolean elementsRemain = true;
while (elementsRemain) {
parser.next();
int event = parser.getEventType();
switch (event) {
case XmlPullParser.START_TAG:
String name = parser.getName();
if (name.equals("store")) {
Log.i("Screen Saver", "entering if store");
String number = parser.getAttributeValue(null, "number");
if (number.equals(store)) {
// located corresponding store, beginning parsing to find associate images and messages
boolean withinStore = true;
while (withinStore) {
parser.next();
if (parser.getEventType() == XmlPullParser.START_TAG) {
String tag = parser.getName();
if (tag.equals("images")) {
parser.nextTag();
while (parser.getEventType() == XmlPullParser.START_TAG && parser.getName().equals("image")) {
if (parser.getAttributeValue(null, "id") != null && (!parser.getAttributeValue(null, "id").equals(""))) {
storeImages += parser.getAttributeValue(null, "id") + ",";
}
parser.nextTag();
if (parser.getEventType() == XmlPullParser.END_TAG) {
parser.nextTag();
}
}
}
parser.next();
if (parser.getEventType() == XmlPullParser.TEXT) {
switch (tag) {
case "message":
managerMessageText += parser.getText();
break;
case "district":
districtMessageText += parser.getText();
break;
case "corporate":
mainMessageText += parser.getText();
break;
default:
break;
}
}
} else if (parser.getEventType() == XmlPullParser.END_TAG && parser.getName().equals("store")) {
withinStore = false;
}
}
parser.next();
}
} else {
}
break;
case XmlPullParser.END_DOCUMENT:
elementsRemain = false;
break;
}
}
} catch (Exception e) {
Log.e("Error reading XML ", " " + e.getMessage());
}
/* LTO images
try {
File managerFile = new File(this.getFilesDir(), store + ".txt");
File universalFile = new File(this.getFilesDir(), "universal.txt");
File districtFile = new File(this.getFilesDir(), "district.txt");
BufferedReader reader = new BufferedReader(new FileReader(managerFile));
managerMessageText = reader.readLine();
reader = new BufferedReader(new FileReader(universalFile));
mainMessageText = reader.readLine();
reader = new BufferedReader(new FileReader(districtFile));
districtMessageText = reader.readLine();
} catch (Exception e) {
Log.e("Error opening file: ", e.getMessage());
}*/
/* images = db.rawQuery("SELECT " + databaseHelper.IMAGE + " FROM " + databaseHelper.TABLE_NAME + " where " + databaseHelper.LTO + " = 1", null);
images.moveToFirst();
while(!images.isAfterLast()) {
imageList.add(BitmapFactory.decodeByteArray(images.getBlob(images.getColumnIndex(databaseHelper.IMAGE)), 0, images.getBlob(images.getColumnIndex(databaseHelper.IMAGE)).length ));
images.moveToNext();
}
images.close(); */
if (storeImages.length() > 1) {
storeImages = storeImages.substring(0, storeImages.length() - 1); // remove trailing comma
}
// get all images that are associated with store
corpImages = db.rawQuery("SELECT " + databaseHelper.SLIDE_IMAGE + " FROM " + databaseHelper.SLIDE_TABLE + " WHERE " + databaseHelper.SLIDE_ID + " IN (" + storeImages + ")", null);
corpImages.moveToFirst();
while (!corpImages.isAfterLast()) {
imageList.add(BitmapFactory.decodeByteArray(corpImages.getBlob(corpImages.getColumnIndex(databaseHelper.SLIDE_IMAGE)), 0, corpImages.getBlob(corpImages.getColumnIndex(databaseHelper.SLIDE_IMAGE)).length));
corpImages.moveToNext();
}
corpImages.close();
db.close();
// begin drawing message bitmaps
if (managerMessageText != "") {
imageList.add(drawText(this, R.drawable.message_background, "Manager Message: \n" + managerMessageText));
}
if (mainMessageText != "") {
imageList.add(drawText(this, R.drawable.message_background, "Corporate Message: \n" + mainMessageText));
}
if (districtMessageText != "") {
imageList.add(drawText(this, R.drawable.message_background, "District Manager Message: \n" + districtMessageText));
}
slide = (ImageView) findViewById(R.id.slider);
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
updateGUI();
}
}, 0, 8000);
}
;
#Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
// unpin screen so it can update
Intent testIntent = new Intent(this, lockActivity.class);
testIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
this.startActivity(testIntent); // unpin screen so it can update
}
private void updateGUI() {
if (reminder.running || hourlyReminder.running) {
this.finish();
} else {
handler.post(runnable);
}
}
}
Thanks so much for any guidance.
Using the decodeResource() method directly attempts to allocate memory for the constructed bitmap & can result OutOfMemory. There are several options to decode bitmaps efficiently.
Setting inJustDecodeBounds of BitmapFactory.Options to true avoids memory allocation in decoding step. It seems you are not using this option.
You don't need to load a full image/bitmap into memory when you just need to show a scaled down/smaller version of it. You can control this by setting inSampleSize of BitmapFactory.Options. It seems you are not using this option as well.
Try using:
options.inJustDecodeBounds = true;
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
etc. options while decoding bitmaps to efficiently handle the memory.
You can find a whole tutorial here: https://developer.android.com/training/displaying-bitmaps/load-bitmap.html
Related
I'm trying to insert some location data on an image generated inside my application (i.e. it's not a picture taken from device camera):
This's saveImage method:
public static String saveImage(Context context, ContentResolver contentResolver, Bitmap source,
String title, String description, Location location) {
File snapshot;
Uri url;
try {
File pictures = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
File rpi = new File(pictures, context.getString(R.string.app_name));
if (!rpi.exists())
if (!rpi.mkdirs())
return null;
snapshot = new File(rpi, title);
OutputStream stream = new FileOutputStream(snapshot);
source.compress(Bitmap.CompressFormat.JPEG, 90, stream);
stream.flush();
stream.close();
if (location != null)
georeferenceImage(snapshot, location);
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.TITLE, title);
values.put(MediaStore.Images.Media.DISPLAY_NAME, title);
if (description != null) {
values.put(MediaStore.Images.Media.DESCRIPTION, description);
}
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
values.put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis());
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {
values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis());
values.put(MediaStore.Images.ImageColumns.BUCKET_ID, snapshot.toString().toLowerCase(Locale.US).hashCode());
values.put(MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME, snapshot.getName().toLowerCase(Locale.getDefault()));
}
values.put("_data", snapshot.getAbsolutePath());
url = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
} catch (Exception ex) {
return null;
}
return (url != null) ? url.toString() : null;
}
This's georeferenceImage() method:
private static boolean georeferenceImage(#NonNull final File image_file, #NonNull final Location location) {
try {
final ExifInterface exif = new ExifInterface(image_file.getAbsolutePath());
exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE, getLat(location));
exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, location.getLatitude() < 0 ? "S" : "N");
exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, getLon(location));
exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, location.getLongitude() < 0 ? "W" : "E");
//exif.setLatLong(location.getLatitude(), location.getLongitude());
//exif.setAltitude(location.getAltitude());
exif.saveAttributes();
} catch (IOException e) {
return false;
}
return true;
}
And these are lat & lon formatting methods:
private static String getLon(#NonNull final Location location) {
String[] degMinSec = Location.convert(location.getLongitude(), Location.FORMAT_SECONDS).split(":");
return degMinSec[0] + "/1," + degMinSec[1] + "/1," + degMinSec[2] + "/1000";
}
private static String getLat(#NonNull final Location location) {
String[] degMinSec = Location.convert(location.getLatitude(), Location.FORMAT_SECONDS).split(":");
return degMinSec[0] + "/1," + degMinSec[1] + "/1," + degMinSec[2] + "/1000";
}
Once saved I see no position data (I tried with different tools with the same result).
I tried also to use setLatLon() and setAltitude() methods without luck.
No exceptions are thrown. Inspecting in debug exif variable prior saveAttributes() call I found only TAG_GPS_LATITUDE_REF and TAG_GPS_LONGITUDE_REF but not TAG_GPS_LATITUDE and TAG_GPS_LONGITUDE.
The problem was hiding around getLat() and getLon() formatters.
This's code works better:
private static String toExifFmt(double angle) {
angle = Math.abs(angle);
final int degree = (int) angle;
angle *= 60;
angle -= (degree * 60.0d);
final int minute = (int) angle;
angle *= 60;
angle -= (minute * 60.0d);
final int second = (int) (angle*1000.0d);
final StringBuilder sb = new StringBuilder();
sb.setLength(0);
sb.append(degree);
sb.append("/1,");
sb.append(minute);
sb.append("/1,");
sb.append(second);
sb.append("/1000");
return sb.toString();
}
I found it here.
Almost everything in my activity is working fine, except for wherever TAG is referenced. TAG gets a red line and says: 'TAG' has private access in 'android.support.v4.app.FragmentActivity'.
MainActivity (without imports)-
public class MainActivity extends AppCompatActivity {
public static final String DATA_PATH = Environment
.getExternalStorageDirectory().toString() + "/MainActivity";
public static final String lang = "eng";
protected Button _button;
protected ImageView _image;
protected TextView _field;
protected String _path;
protected boolean _taken;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String[] paths = new String[] { DATA_PATH, DATA_PATH + "tessdata/" };
for (String path : paths) {
File dir = new File(path);
if (!dir.exists()) {
if (!dir.mkdirs()) {
Log.v(TAG, "ERROR: Creation of directory " + path + " on sdcard failed");
return;
} else {
Log.v(TAG, "Created directory " + path + " on sdcard");
}
}
}
if (!(new File(DATA_PATH + "tessdata/" + lang + ".traineddata")).exists()) {
try {
AssetManager assetManager = getAssets();
InputStream in = assetManager.open("tessdata/" + lang + ".traineddata");
//GZIPInputStream gin = new GZIPInputStream(in);
OutputStream out = new FileOutputStream(DATA_PATH
+ "tessdata/" + lang + ".traineddata");
// Transfer bytes from in to out
byte[] buf = new byte[1024];
int len;
//while ((lenf = gin.read(buff)) > 0) {
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
//gin.close();
out.close();
Log.v(TAG, "Copied " + lang + " traineddata");
} catch (IOException e) {
Log.e(TAG, "Was unable to copy " + lang + " traineddata " + e.toString());
}
}
_image = ( ImageView ) findViewById( R.id.image );
_field = ( TextView ) findViewById( R.id.field );
_button = ( Button ) findViewById( R.id.button );
_button.setOnClickListener( new ButtonClickHandler() );
_path = Environment.getExternalStorageDirectory() + "/Login Data.jpg";
}
public class ButtonClickHandler implements View.OnClickListener
{
public void onClick( View view ){
startCameraActivity();
}
}
protected void startCameraActivity()
{
File file = new File( _path );
Uri outputFileUri = Uri.fromFile( file );
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE );
intent.putExtra( MediaStore.EXTRA_OUTPUT, outputFileUri );
startActivityForResult( intent, 0 );
}
protected void onPhotoTaken()
{
_taken = true;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 4;
Bitmap bitmap = BitmapFactory.decodeFile( _path, options );
_image.setImageBitmap(bitmap);
_field.setVisibility( View.GONE );
ExifInterface exif = new ExifInterface(_path);
int exifOrientation = exif.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
int rotate = 0;
switch (exifOrientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
rotate = 90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
rotate = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
rotate = 270;
break;
}
if (rotate != 0) {
int w = bitmap.getWidth();
int h = bitmap.getHeight();
// Setting pre rotate
Matrix mtx = new Matrix();
mtx.preRotate(rotate);
// Rotating Bitmap & convert to ARGB_8888, required by tess
bitmap = Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, false);
}
bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
TessBaseAPI baseApi = new TessBaseAPI();
baseApi.init(DATA_PATH, lang);
baseApi.setImage(bitmap);
String recognizedText = baseApi.getUTF8Text();
baseApi.end();
}
#Override
protected void onSaveInstanceState( Bundle outState ) {
outState.putBoolean( MainActivity.PHOTO_TAKEN, _taken );
}
#Override
protected void onRestoreInstanceState( Bundle savedInstanceState)
{
Log.i( "MakeMachine", "onRestoreInstanceState()");
if( savedInstanceState.getBoolean( MainActivity.PHOTO_TAKEN ) ) {
onPhotoTaken();
}
}
You should define a constant for your tag in MainActivity:
private static final String TAG = "MainActivity"
try the following
private static final String TAG = MainActivity.class.getSimpleName();
You can use this field in your any Activity or Fragment.
Well that's just an Android's way of telling us that we haven't defined TAG. To define the TAG in the current file, we can go to MainActivity Class and type "logt", you will get some auto code suggestions from Android studio, press enter there and you will get following code
private static final String TAG = "MainActivity";
Once you add this to your code, your error will be gone
Practical note: following is the better approach
private static final String TAG = MainActivity.class.getSimpleName();
as compared to:
private static final String TAG = "MainActivity";
I'm in trouble with this android java class.
The goal that I'm trying to reach with this activity is:
start camera-->take photo-->recognize text-->(tts and recognized text in the edittext)
TTS would had to start automatically after the text recognition. But it didn't. The recognized text also must appear in the edit text (and it's work)
I'm ok with the three first steps. TTS gives me an issue: "speak failed: not bound to TTS engine". I'm trying to understand where is the problem. I also followed some guide to use tts, I think the problem is about stop or shutdown of tts. Any idea? Thanks a lot
Code
public class CameraActivity extends Activity {
public TextToSpeech tts1;
public String voce;
public String text;
public static final String DATA_PATH = Environment
.getExternalStorageDirectory().toString() + "/OcrTesiDiLaurea/";
public static final String lingua= Locale.getDefault().getISO3Language();
public static final String lang = lingua;
private static final String TAG = MainActivity.class.getName();
protected Button _button;
protected EditText _field;
protected String _path;
protected boolean _taken;
protected static final String PHOTO_TAKEN = "foto catturata";
#Override
public void onDestroy(){
if(tts1 !=null){
tts1.stop();
tts1.shutdown();
}
super.onDestroy();
}
#Override
public void onCreate(Bundle savedInstanceState) {
String[] paths = new String[] { DATA_PATH, DATA_PATH + "tessdata/" };
for (String path : paths) {
File dir = new File(path);
if (!dir.exists()) {
if (!dir.mkdirs()) {
Log.v(TAG, "ERRORE: creazione directory " + path + " in memoria fallita");
return;
} else {
Log.v(TAG, "creazione directory " + path + " eseguita con successo");
}
}
}
if (!(new File(DATA_PATH + "tessdata/" + lang + ".traineddata")).exists()) {
try {
AssetManager assetManager = getAssets();
InputStream in = assetManager.open("tessdata/" + lang + ".traineddata");
OutputStream out = new FileOutputStream(DATA_PATH
+ "tessdata/" + lang + ".traineddata");
// Transferimento dati
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
Log.v(TAG, "file " + lang + " copiato con successo in traineddata");
} catch (IOException e) {
Log.e(TAG, "impossibile copiare " + lang + " traineddata " + e.toString());
}
}
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
_field = (EditText) findViewById(R.id.field);
_button = (Button) findViewById(R.id.button);
_button.setOnClickListener(new ButtonClickHandler());
_path = DATA_PATH + "/ocr.jpg";
tts1=new TextToSpeech(getApplicationContext(),
new TextToSpeech.OnInitListener() {
#Override
public void onInit(int status) {
if(status != TextToSpeech.ERROR){
tts1.setLanguage(Locale.getDefault());
}
}
});
}
public class ButtonClickHandler implements View.OnClickListener {
public void onClick(View view) {
Log.v(TAG, "avvio fotocamera");
startCameraActivity();
}
}
// http://labs.makemachine.net/2010/03/simple-android-photo-capture/
protected void startCameraActivity() {
File file = new File(_path);
Uri outputFileUri = Uri.fromFile(file);
final Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
startActivityForResult(intent, 0);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.i(TAG, "resultCode: " + resultCode);
if (resultCode == -1) {
onPhotoTaken();
} else {
Log.v(TAG, "User cancelled");
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putBoolean(CameraActivity.PHOTO_TAKEN, _taken);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
Log.i(TAG, "onRestoreInstanceState()");
if (savedInstanceState.getBoolean(CameraActivity.PHOTO_TAKEN)) {
onPhotoTaken();
}
}
protected void onPhotoTaken() {
_taken = true;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 4;
Bitmap bitmap = BitmapFactory.decodeFile(_path, options);
try {
ExifInterface exif = new ExifInterface(_path);
int exifOrientation = exif.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
Log.v(TAG, "Orient: " + exifOrientation);
int rotate = 0;
switch (exifOrientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
rotate = 90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
rotate = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
rotate = 270;
break;
}
Log.v(TAG, "Rotation: " + rotate);
if (rotate != 0) {
// Getting width & height of the given image.
int w = bitmap.getWidth();
int h = bitmap.getHeight();
// Setting pre rotate
Matrix mtx = new Matrix();
mtx.preRotate(rotate);
// Rotating Bitmap
bitmap = Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, false);
}
bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
} catch (IOException e) {
Log.e(TAG, "Couldn't correct orientation: " + e.toString());
}
Log.v(TAG, "Inizio utilizzo librerie tesseract");
TessBaseAPI baseApi = new TessBaseAPI();
baseApi.setDebug(true);
baseApi.init(DATA_PATH, lang);
baseApi.setImage(bitmap);
String recognizedText = baseApi.getUTF8Text();
baseApi.end();
_field.getText().clear();
Log.v(TAG, "OCRED TEXT: " + recognizedText);
if ( lang.equalsIgnoreCase("eng") ) {
recognizedText = recognizedText.replaceAll("[^a-zA-Z0-9]+", " ");
}
if ( lang.equalsIgnoreCase("ita") ) {
recognizedText = recognizedText.replaceAll("[^a-zA-Z0-9]+", " ");
}
recognizedText = recognizedText.trim();
if ( recognizedText.length() != 0 ) {
_field.setText(_field.getText().toString().length() == 0 ? recognizedText : _field.getText() + " " + recognizedText);
_field.setSelection(_field.getText().toString().length());
}
voce=recognizedText;
}
public void convertTextToSpeech() {
text = voce;
if (null == text || "".equals(text)) {
text = "NON POSSO PRONUNCIARE NESSUNA PAROLA, MANCA IL TESTO";
}
tts1.speak(text, TextToSpeech.QUEUE_FLUSH, null);
}
}
It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
i am developing an android application that will receive MMS from specific number and show it in my application, I found this code but when i run it, Nothing Happened
public class MMSActivity extends Activity {
ImageView imageView1;
TextView t;
MMSMonitor myMonitor = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
t= (TextView) findViewById(R.id.t);
imageView1= (ImageView) findViewById(R.id.imageView1);
startMMSMonitor();
}
#Override
public void onDestroy()
{
super.onDestroy();
if(myMonitor != null)
myMonitor.stopMMSMonitoring();
}
protected void startMMSMonitor()
{
Context ctx = this;
ContentResolver cr = this.getContentResolver();
myMonitor = new MMSMonitor(cr, ctx);
myMonitor.startMMSMonitoring();
}
public void setMMSText(String text)
{
//Do whatever you want
}
public void setMMSImageData(byte[] data, String fileType)
{
//Do whatever you want
}
public class MMSMonitor {
private ContentResolver contentResolver = null;
private Handler mmshandler = null;
private ContentObserver mmsObserver = null;
public String mmsNumber = "";
public boolean monitorStatus = false;
public String activationCode;
int mmsCount = 0;
String lastMMSTxId = null;
String code;
public MMSMonitor(final ContentResolver contentResolver, final Context mainContext) {
this.contentResolver = contentResolver;
mmshandler = new MMSHandler();
mmsObserver = new MMSObserver(mmshandler);
System.out.println( "MMSMonitor :: ***** Start MMS Monitor *****");
}
public void startMMSMonitoring() {
try {
monitorStatus = false;
if (!monitorStatus) {//do not get it
//it is observe anychange like delete or incoming MMS etc...
//ContentObserver is used to get notified if the data residing in the data set has changed.
//So it is used to observe the data source for changes.
//Content providers manage access to a structured set of data
//Content providers are the standard interface that connects data
//in one process with code running in another process.
//When you want to access data in a content provider, you use the ContentResolver object
contentResolver.registerContentObserver(Uri.parse("content://mms-sms"), true, mmsObserver);
Uri uriMMSURI = Uri.parse("content://mms");
Cursor mmsCur = contentResolver.query(uriMMSURI, null, "msg_box = 4", null, "_id");
if (mmsCur != null && mmsCur.getCount() > 0) {
//Number of MMS
mmsCount = mmsCur.getCount();
System.out.println( "MMSMonitor :: Init MMSCount ==" + mmsCount);
}
}
} catch (Exception e) {
System.out.println( "MMSMonitor :: startMMSMonitoring Exception== "+ e.getMessage());
}
}
public void stopMMSMonitoring() {
try {
monitorStatus = false;
if (!monitorStatus){
contentResolver.unregisterContentObserver(mmsObserver);
}
} catch (Exception e) {
System.out.println( "MMSMonitor :: stopMMSMonitoring Exception == "+ e.getMessage());
}
}
//A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue.
class MMSHandler extends Handler {
public void handleMessage(final Message msg) {
//Log("MMS", "MMSMonitor :: Handler");
}
}
class MMSObserver extends ContentObserver {
private Handler mms_handle = null;
public MMSObserver(final Handler mmshandle) {
super(mmshandle);
mms_handle = mmshandle;
}
public void onChange(final boolean bSelfChange) {
super.onChange(bSelfChange);
//Log("MMS", "MMSMonitor :: Onchange");
Thread thread = new Thread() {
public void run() {
try {
monitorStatus = true;
// Send message to Activity
Message msg = new Message();
mms_handle.sendMessage(msg);
// Getting the mms count
Uri uriMMSURI = Uri.parse("content://mms/");
Cursor mmsCur = contentResolver.query(uriMMSURI, null, "msg_box = 4 or msg_box = 1", null,"_id");
int currMMSCount = 0;
if (mmsCur != null && mmsCur.getCount() > 0) {
currMMSCount = mmsCur.getCount();
}
if (currMMSCount > mmsCount) {
mmsCount = currMMSCount;
mmsCur.moveToLast();
// get id , subject
//String subject = mmsCur.getString(6);
//int id = Integer.parseInt(mmsCur.getString(0));
String subject = mmsCur.getString(mmsCur.getColumnIndex("sub"));
int id = Integer.parseInt(mmsCur.getString(mmsCur.getColumnIndex("_id")));
System.out.println( "MMSMonitor :: _id == " + id);
System.out.println( "MMSMonitor :: Subject == " + subject);
byte[] imgData = null;
String message = "";
String address = "";
String fileName = "";
String fileType = "";
String direction = "";
// GET DIRECTION
boolean isIncoming = false;
//int type = Integer.parseInt(mmsCur.getString(12));
int type = Integer.parseInt(mmsCur.getString(mmsCur.getColumnIndex("m_type")));
if (type == 128) {
direction = "0";
System.out.println( "MMSMonitor :: Type == Outgoing MMS");
} else {
isIncoming = true;
direction = "1";
System.out.println( "MMSMonitor :: Type == Incoming MMS");
}
// Get Parts
Uri uriMMSPart = Uri.parse("content://mms/part");
Cursor curPart = contentResolver
.query(uriMMSPart, null, "mid = " + id, null, "_id");
System.out.println( "MMSMonitor :: parts records length == "+ curPart.getCount());
curPart.moveToLast();
do {
//String contentType = curPart.getString(3);
//String partId = curPart.getString(0);
String contentType = curPart.getString(curPart.getColumnIndex("ct"));
String partId = curPart.getString(curPart.getColumnIndex("_id"));
System.out.println( "MMSMonitor :: partId == " + partId);
System.out.println( "MMSMonitor :: part mime type == "+ contentType);
// Get the message
if (contentType.equalsIgnoreCase("text/plain"))
{
System.out.println("MMSMonitor :: ==== Get the message start ====");
byte[] messageData = readMMSPart(partId);
if (messageData != null && messageData.length > 0)
message = new String(messageData);
if(message == ""){
Cursor curPart1 = contentResolver
.query(uriMMSPart, null, "mid = " + id +
" and _id =" + partId,null, "_id");
for (int i = 0; i < curPart1.getColumnCount(); i++)
{
System.out.println("MMSMonitor :: Column Name : " +
curPart1.getColumnName(i));
}
curPart1.moveToLast();
message = curPart1.getString(13);
}
System.out.println("MMSMonitor :: Txt Message == " + message);
//SEND DATA TO ACTIVITY
setMMSText(message);
}
// Get Image
else if (isImageType(contentType) == true) {
System.out.println("MMSMonitor :: ==== Get the Image start ====");
fileName = "mms_" + partId;
fileType = contentType;
imgData = readMMSPart(partId);
System.out.println( "MMSMonitor :: Iimage data length == "+ imgData.length);
//SEND DATA TO ACTIVITY
setMMSImageData(imgData, fileType);
}
} while (curPart.moveToPrevious());
}
} catch (Exception e) {
System.out.println( "MMSMonitor Exception:: "+ e.getMessage());
}
}
};
thread.start();
}
}
private byte[] readMMSPart(String partId) {
byte[] partData = null;
Uri partURI = Uri.parse("content://mms/part/" + partId);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
InputStream is = null;
try {
System.out.println("MMSMonitor :: Entered into readMMSPart try..");
ContentResolver mContentResolver = contentResolver;
is = mContentResolver.openInputStream(partURI);
byte[] buffer = new byte[256];
int len = is.read(buffer);
while (len >= 0) {
baos.write(buffer, 0, len);
len = is.read(buffer);
}
partData = baos.toByteArray();
//Log.i("", "Text Msg :: " + new String(partData));
} catch (IOException e) {
System.out.println( "MMSMonitor :: Exception == Failed to load part data");
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
System.out.println("Exception :: Failed to close stream");
}
}
}
return partData;
}
private boolean isImageType(String mime) {
boolean result = false;
if (mime.equalsIgnoreCase("image/jpg")
|| mime.equalsIgnoreCase("image/jpeg")
|| mime.equalsIgnoreCase("image/png")
|| mime.equalsIgnoreCase("image/gif")
|| mime.equalsIgnoreCase("image/bmp")) {
result = true;
}
return result;
}
}
}
//=====================
}
any answer i will appreciate it,
also
what this statement suppose be to do ?
Cursor mmsCur = contentResolver.query(uriMMSURI, null, "msg_box = 4 or msg_box = 1", null,"_id");
I think your approach isn't even the right one.
Afaik you have to register a broadcastreceiver and handle/implement this in your app in order to achieve what you want.
See
Android MMS Broadcast receiver
Detecting new MMS (Android 2.1)
Detecting MMS messages on Android
There are all infos u need ;)
I have a slideshow in my app and some text associated it with every slide. the text and images are dynamic. How can i retain the text of a particular slide on orientation change so that after orientation change the view remains same.I basically want to know the slide number or index on which the orientation was changed.
What i am doing is as follows:
#Override
public Object onRetainNonConfigurationInstance() {
ArrayList<Object> objList = new ArrayList<Object>();
Bitmap bitmapList[] = null;
String data = "";
try {
bitmapList = new Bitmap[slides.size()];
Log.e("ON", "onRetainNonConfigurationInstance() ");
if (gallery != null) {
for (int i = 0; i < imgViews.length; i++) {
LoaderImageView loaderImageView = imgViews[i];
if (loaderImageView != null) {
Bitmap bitmap = loaderImageView.getImageBitmap();
data = slides.get(i).getBody();
//System.out.println("the body text is: " + data);
if (bitmap != null) {
bitmapList[i] = new BitmapDrawable(bitmap).getBitmap();
}
}
}
}
objList.add(bitmapList);
objList.add(isDisplayingText);
objList.add(data);
} catch (Exception e) {
Log.e("Exception ", "LargeSlideShow.onRetain Message = " + e.toString());
} catch (Error e) {
Log.e("Error ", "LargeSlideShow.onRetain Message = " + e.toString());
}
return objList;
}
and in onCreate am doing it this way:
onCreate()
{ ...
ArrayList<Object> obj1 = (ArrayList<Object>) getLastNonConfigurationInstance();
if (obj1 != null) {
bitmaps = (Bitmap[]) obj1.get(0);
boolean isText = (Boolean) obj1.get(1);
String data = (String) obj1.get(2);
System.out.println("The Text received in on Create is: " + data);
if (isText == true) {
int vis = disText.getVisibility();
if (vis == View.GONE) {
String formattedBody = makeFormattedBody(data);
webView.loadData(formattedBody, "webView/html", "utf-8");
disText.setVisibility(View.VISIBLE);
disText.startAnimation(animShow);
isDisplayingText = true;
} else if (vis == View.VISIBLE) {
disText.startAnimation(animHide);
disText.setVisibility(View.GONE);
isDisplayingText = false;
}
}
... }
where am i missing the shot, please let me know. any help is appreciated.
You need to override the "onConfigurationChanged" function in your activity and enable the activity to handle the change in the manifest.xml:
<activity android:name=".SlideView" android:configChanges="orientation"> </activity>
Then you may setUp your View again:
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
setContentView(R.layout.oneSlide);
setUpView(); // configure the view e.g. add the picture and the text
}