FileObserver not reacting to CREATE - android

I'm trying to make an app that will react to screenshots folder and do a toast for beginning,
I'm a new developer and this is my first time using file observer so I can only guess I've made a lot of mistakes.
The problem is there is no toast or log upon taking a screenshot.
Here is the code in my observer class:
public class listeningInit extends FileObserver {
private static final String TAG = "File listener";
public String absolutePath;
public listeningInit(String path) {
super(path, FileObserver.ALL_EVENTS);
absolutePath = path;
}
#Override
public void onEvent(int event, String path) {
if ((FileObserver.CREATE & event)!=0) {
Log.v(TAG, absolutePath + "/" + path + " is created\n");
Context context = getContext();
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(context, "Folder action!", duration);
toast.show();
}
}
private Context getContext() {
// TODO Auto-generated method stub
return null;
}
and here's the code on activity that does .startWatching
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listeningInit startObs = new listeningInit("/Pictures/Screenshots/");
startObs.startWatching();
//Checking if this is a first run
Boolean firstRun = false;
SharedPreferences run = getSharedPreferences("MYPREFS", 0);
firstRun = run.getBoolean("fr", true);
//if true launch tutorial activity
if(firstRun == true){
Intent k = new Intent(MainActivity.this, Tutorial.class);
startActivity(k);
}
}
There's no errors thrown by the code, it's just not responding and I don't have a slight clue on why that might be.

Related

Take picture in non-activity class

I want to take picture in an non-activity class. However I get error: Attempt to invoke virtual method on a null object reference. Here is my code:
MainAcvitity.java
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Print myprint = new Print();
myprint.Picture();
}
Print.java
public class Print {
private static final String TAG = "Secret";
Context context;
public void Picture() {
Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
((Activity) this.context).startActivityForResult(intent, 1);
Log.v(TAG, "I took a picture.");
}
}
I don't know what goes wrong. Can you tell me why this happens and how can I fix it? I don't want my Print class to be an Activity class. I know how how to take picture if Print is an Activity class. 0.0
Because your context is null. You haven't init it yet.
If you want to create a class to open your camera, try this:
public class Print{
private static final String TAG = "Secret";
private Context context;
private File photoCaptured;
public Print(Context context) {
this.context = context;
}
public void openCamera() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
String timeStamp = System.currentTimeMillis() + "";
String fileName = "JPEG_" + timeStamp;
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
photoCaptured = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES),
fileName + ".jpg");
} else {
String dir = Environment.getExternalStorageDirectory() + File.separator + "myDirectory";
//create folder
File folder = new File(dir); //folder name
if (!folder.exists()) {
folder.mkdirs();
}
//create file
photoCaptured = new File(dir, fileName + ".jpg");
}
Uri temUri = Uri.fromFile(photoCaptured);
intent.putExtra(MediaStore.EXTRA_OUTPUT, temUri);
intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0);
if (intent.resolveActivity(context.getPackageManager()) != null) {
((AppCompatActivity) context).startActivityForResult(intent, REQUEST_TAKE_PHOTO);
}
}
}
Then in your MainActivity, init Print and use it.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Print myprint = new Print(this);
myprint.openCamera();
}
For your question, just init your Print class and it will work. (Just for your case only, but this is not the best approach!!!)
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Print myprint = new Print(this);
myprint.Picture()
}

How to set directory for sending files using Android Beam

I am working on an app that allows user to select a file from external storage and send it using Android Beam.
Here is the FileBrowser Activity to select a file from a directory and return the file name and directory path back to main activity:
public class FileBrowser extends Activity {
private String root;
private String currentPath;
private ArrayList<String> targets;
private ArrayList<String> paths;
private File targetFile;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_file_browser);
getActionBar().setDisplayHomeAsUpEnabled(true);
root = "/";
currentPath = root;
targets = null;
paths = null;
targetFile = null;
showDir(currentPath);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_file_browser, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
NavUtils.navigateUpFromSameTask(this);
return true;
}
return super.onOptionsItemSelected(item);
}
public void selectDirectory(View view) {
File f = new File(currentPath);
targetFile = f;
//Return target File to activity
returnTarget();
}
public void setCurrentPathText(String message)
{
TextView fileTransferStatusText = (TextView) findViewById(R.id.current_path);
fileTransferStatusText.setText(message);
}
private void showDir(String targetDirectory){
setCurrentPathText("Current Directory: " + currentPath);
targets = new ArrayList<String>();
paths = new ArrayList<String>();
File f = new File(targetDirectory);
File[] directoryContents = f.listFiles();
if (!targetDirectory.equals(root))
{
targets.add(root);
paths.add(root);
targets.add("../");
paths.add(f.getParent());
}
for(File target: directoryContents)
{
paths.add(target.getPath());
if(target.isDirectory())
{
targets.add(target.getName() + "/");
}
else
{
targets.add(target.getName());
}
}
ListView fileBrowserListView = (ListView) findViewById(R.id.file_browser_listview);
ArrayAdapter<String> directoryData = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, targets);
fileBrowserListView.setAdapter(directoryData);
fileBrowserListView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> arg0, View view, int pos,long id) {
File f = new File(paths.get(pos));
if(f.isFile())
{
targetFile = f;
returnTarget();
//Return target File to activity
}
else
{
//f must be a dir
if(f.canRead())
{
currentPath = paths.get(pos);
showDir(paths.get(pos));
}
}
}
});
}
public void returnTarget()
{
Intent returnIntent = new Intent();
returnIntent.putExtra("file", targetFile);
returnIntent.putExtra("path", currentPath);
setResult(RESULT_OK, returnIntent);
finish();
}
}
Here is the code for MainActivity where the file returned by FileBrowser Activity is send using android beam:
public class MainActivity extends Activity {
private NfcAdapter nfcAdapter;
public final int fileRequestID = 98;
String name;
String[] extension={".png",".docx",".jpeg",".pdf",".doc"};
ArrayList <String>supportedExtension=new ArrayList<String>(Arrays.asList(extension));
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
PackageManager pm = this.getPackageManager();
// Check whether NFC is available on device
if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC)) {
// NFC is not available on the device.
Toast.makeText(this, "The device does not has NFC hardware.",
Toast.LENGTH_SHORT).show();
}
// Check whether device is running Android 4.1 or higher
else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
// Android Beam feature is not supported.
Toast.makeText(this, "Android Beam is not supported.",
Toast.LENGTH_SHORT).show();
}
else {
// NFC and Android Beam file transfer is supported.
Toast.makeText(this, "Android Beam is supported on your device.",
Toast.LENGTH_SHORT).show();
}
}
public void browseForFile(View view) {
Intent clientStartIntent = new Intent(this, FileBrowser.class);
startActivityForResult(clientStartIntent, fileRequestID);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
//fileToSend
boolean filePathProvided;
File fileToSend;
if (resultCode == Activity.RESULT_OK && requestCode == fileRequestID) {
//Fetch result
File targetDir = (File) data.getExtras().get("file");
String path = (String)data.getExtras().get("path");
Log.i("Path=",path);
if(targetDir.isFile())
{
if(targetDir.canRead()) {
try{
String ext=targetDir.getName().substring(targetDir.getName().lastIndexOf("."));
if (supportedExtension.contains(ext)) {
fileToSend = targetDir;
filePathProvided = true;
setTargetFileStatus(targetDir.getName() + " selected for file transfer");
Button btn = (Button) findViewById(R.id.send);
btn.setVisibility(View.VISIBLE);
name = targetDir.getName();
}
else{
Toast.makeText(getApplicationContext(), "File with this extension cannot be printed",
Toast.LENGTH_LONG).show();
}
}catch (Exception e){e.printStackTrace();}
}
else
{
filePathProvided = false;
setTargetFileStatus("You do not have permission to read the file " + targetDir.getName());
}
}
else
{
filePathProvided = false;
setTargetFileStatus("You may not transfer a directory, please select a single file");
}
}
}
public void setTargetFileStatus(String message)
{
TextView targetFileStatus = (TextView) findViewById(R.id.selected_filename);
targetFileStatus.setText(message);
}
public void sendFile(View view) {
nfcAdapter = NfcAdapter.getDefaultAdapter(this);
// Check whether NFC is enabled on device
if(!nfcAdapter.isEnabled()){
Toast.makeText(this, "Please enable NFC.", Toast.LENGTH_SHORT).show();
startActivity(new Intent(Settings.ACTION_NFC_SETTINGS));
}
else if(!nfcAdapter.isNdefPushEnabled()) {
Toast.makeText(this, "Please enable Android Beam.",
Toast.LENGTH_SHORT).show();
startActivity(new Intent(Settings.ACTION_NFCSHARING_SETTINGS));
}
else {
Uri[] mFileUris = new Uri[1];
String fileName=name;
// Retrieve the path to the user's public pictures directory
File fileDirectory = Environment
.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
File fileToTransfer;
fileToTransfer = new File(fileDirectory, fileName);
fileToTransfer.setReadable(true, false);
mFileUris[0] = Uri.fromFile(fileToTransfer);
nfcAdapter.setBeamPushUris(mFileUris, this);
}
}
}
Now, as you can see in my MainActivity, I am setting my directory as Pictures.
File fileDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
My question is How can I dynamically change my directory every time based on the actual directory value obtained from FileBrowser Activity?
I have already went through the android documentation of How to send files using Android Beam, but didn't find it much useful for my problem. I also went through the android documentation of Environment, but couldn't understand much.
Any help regarding this will really be appreciated. Thanks in advance!
You already have the file selected in OnActivityResult method. Just change
mFileUris[0] = Uri.fromFile(fileToTransfer);
to
mFileUris[0] = Uri.fromFile(targetDir);

Why is the android thread starting on its own

I have a written a receiver for a NEW_OUTGOING_CALL intent (static receiver). In order not to hold the system, I do the lengthy part of the process in a AsyncTask.
Based on the number dialed, I may or may not start the AsyncTask (and proceed with regular processing). However, the tasks starts on its own, with the right param passed, and I cant figure out how !!
I've grep'ed the project, and there are no other calls to LongOperation other than the one in the CallOneShot function - but the traces surrounding the 'new' statement do not appear.
How can this happen ?
Please find the code attached, sorry for the length, I've tried to cut it down a bit
Thanks for the help
J.
package com.iper.phoneeco;
public class MyReceiver extends BroadcastReceiver {
private static final String TAG = "XXBroadcastReceiver";
FileWriter fDevLog;
MyPrefs myprefs=null;
public final static String EXTRA_MESSAGE = "com.iper.phoneeco.msg1";
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equalsIgnoreCase("android.intent.action.NEW_OUTGOING_CALL"))
{
Log.d(TAG,"OUTGOING CALL RECEIVED");
String phoneNumber = getResultData();
if (phoneNumber == null) {
// No reformatted number, use the original
phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
}
Log.d(TAG,"phone number:"+phoneNumber);
if (IsToProcess(phoneNumber)) {
Log.d (TAG,"Trapping the call");
// Lets Roll
CallOneShot(phoneNumber);
// and prevent other apps from calling as well
setResultData(null);
// abortBroadcast();
}
else {
Log.d (TAG,"Standard processing");
Toast.makeText(context, "standard processing" , Toast.LENGTH_LONG).show();
}
Log.d (TAG,"Finished processing intent");
}
//
// check is number against a list of exceptions, that we dont handle
//
private boolean IsToProcess(String num){
String[] excluded = {"15","17","18","112","911","991","08.*","^\\*.*","^#.*"};
for (String ex : excluded){
Log.d(TAG,"Exclusion test: "+ex + "versus: "+num);
if (num.matches(ex)) {
Log.d(TAG,"Exclusion FOUND: "+ex);
return false;
}
}
if (num.length() < myprefs.minLen) {
Log.d(TAG,"Exclusion FOUND: Numero trop court");
return false;
}
Log.d(TAG,"Exclusion not found: ");
return true;
}
//
// Displays a toast
//
void MyToast(String s, int col, int dur ) {
Toast toast=Toast.makeText(myprefs.ctx, s, dur);
toast.setGravity(Gravity.CENTER_HORIZONTAL, 0, 0);
toast.getView().setBackgroundColor(col );
LinearLayout toastLayout = (LinearLayout) toast.getView();
TextView toastTV = (TextView) toastLayout.getChildAt(0);
toastTV.setTextSize(20);
toast.show();
}
void MyToast(String s, int col) {
MyToast(s,col,Toast.LENGTH_LONG);
}
public void CallOneShot(String phoneNumber) {
Log.d (TAG,"CallOneShot");
MyToast (myprefs.ctx.getResources().getString(R.string.callbackipg)+" "+phoneNumber,Color.BLUE);
new LongOperation().execute(phoneNumber);
}
//
// the meat....
//
public class LongOperation extends AsyncTask<String, Void, String> {
String numToCall;
#Override
protected String doInBackground(String... params) {
int bytesRead;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(1024);
byte[] buffer = new byte[1024];
String msgres;
String response;
Log.d(TAG, "Clientthread started");
numToCall=params[0];
Log.d(TAG, "numTocall"+numToCall);
// and add to the call log
ContentValues values = new ContentValues();
values.put(CallLog.Calls.NUMBER, numToCall);
values.put(CallLog.Calls.DATE, System.currentTimeMillis());
values.put(CallLog.Calls.DURATION, 0);
values.put(CallLog.Calls.TYPE, CallLog.Calls.OUTGOING_TYPE);
values.put(CallLog.Calls.NEW, 1);
values.put(CallLog.Calls.CACHED_NAME, "");
values.put(CallLog.Calls.CACHED_NUMBER_TYPE, 0);
values.put(CallLog.Calls.CACHED_NUMBER_LABEL, "");
Log.d(TAG, "Inserting call log placeholder for " + numToCall);
ContentResolver resolver = myprefs.ctx.getContentResolver();
resolver.insert(CallLog.Calls.CONTENT_URI, values);
response=myprefs.ctx.getResources().getString(R.string.errundef);
return response;
}
protected void onPostExecute (String s) {
if (!s.equals("ok")) {
Log.d(TAG,"OnPostExecute - failed: "+s);
MyToast (myprefs.ctx.getResources().getString(R.string.errcallback)+"\n"+s,Color.RED);
}
}
}
}
Have you assign value to myprefs. It seems that you have initialized it to null and never assign it to any value
ok - stupid me is the answer - I had changed the name of the package, and an old version of the package was still on the emulator, trapping the intent ! once I removed it, it all went back to normal...
Many thanks for your help anyway

Weird behaviour of activity lifecycle - after onResume() also onPause() called ...why?

I have a Form with edittexts and a button to call the camera with an intent (return a bitmap that is put into the imageview)...From the portrait mode i enter all edittext filed and then click the camera button which forwards me to the camera - in the camera i take a picture after what I get returned to Activity 1 (staying in portrait orientation - and all editext fields are restore in onRestoreInstanceState()) - and the last callback method of Activity 1 is onResume() (what is ok) - But the problem comes when I make an orientation change from this portrait to landscape mode - the callback methods are following
So the last callback orientation change is onPause(). I do not understand why? The problem is that onSaveInstanceState is called prior of onPause - so when I turn back to portrait mode everything will be empty (editexts, imageview..) - this strange behavior continues on every orientation change (the onPause() is called last).
I am sure this problem has to do something with the taking an image (startInentforResult....) because everything (editext fields) works fine on orientation change prior to taking an image...sometimes I can also take an image and it works fine, but in most cases not...
So my question is what is it that "drives" my Activity up to the onPause() method instead up to the onResume()?
Thanks, I would really appreciate if somebody knows the solution because I am struggling with this already a few days and could not find the solution.
The project has many classes but this is the activity code (Important to note is that the problem arises only when I take an image from camera app, after that the activity lifecycle goes crazy - also this activity is called from the main activity with 'startIntentforResult()'. I do not use 'android:configChanges="orientation|keyboardHidden"' to stop the recreatioin ):
public class NewCounterActivity extends Activity {
Button btnCreate;
Button btnCancel;
Button btnTakeImg;
ImageView counterImgView;
CheckBox existsDamage;
EditText inputNameFirst;
EditText inputNameLast;
EditText inputAdresse;
EditText inputCounterID;
EditText inputCounterValue;
EditText inputDescription;
TextView registerErrorMsg;
DatabaseHandler db;
//Data to be submitted
String nameFirst;
String nameLast;
String adresse;
String counterID;
String counterValue;
String countDescript;
String existsDmg;
Bitmap counterBitmap;
Bitmap recievedBitmap;
String longitude;
String latitude;
LocationTracker gps;
// JSON Response node names
private static String KEY_SUCCESS = "success";
private static String KEY_ERROR = "error";
private static String KEY_ERROR_MSG = "error_msg";
//The dimensions of the ImageView
int targetW;
int targetH;
// Some lifecycle callbacks so that the image can survive orientation change
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.e("onSaveInstanceState", "fadsfass");
outState.putParcelable("bitmap", counterBitmap);
outState.putString("fname", inputNameFirst.getText().toString());
outState.putString("lname", inputNameLast.getText().toString());
outState.putString("adrese", inputAdresse.getText().toString());
outState.putString("cID", inputCounterID.getText().toString());
outState.putString("cValue", inputCounterValue.getText().toString());
outState.putString("Descript", inputDescription.getText().toString());
outState.putString("ErrorMsg", registerErrorMsg.getText().toString());
outState.putBoolean("damageCheck", existsDamage.isChecked());
((MyApplicationClass) getApplication()).detach(this);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Log.e("onRestoreInstanceState", "fadsfass");
counterBitmap = savedInstanceState.getParcelable("bitmap");
counterImgView.setImageBitmap(counterBitmap);
inputNameFirst.setText(savedInstanceState.getString("fname"));
inputNameLast.setText(savedInstanceState.getString("lname"));
inputAdresse.setText(savedInstanceState.getString("adrese"));
inputCounterID.setText(savedInstanceState.getString("cID"));
inputCounterValue.setText(savedInstanceState.getString("cValue"));
inputDescription.setText(savedInstanceState.getString("Descript"));
registerErrorMsg.setText(savedInstanceState.getString("ErrorMsg"));
existsDamage.setChecked(savedInstanceState.getBoolean("damageCheck"));
((MyApplicationClass) getApplication()).attach(this);
}
#Override
public void onContentChanged() {
// TODO Auto-generated method stub
super.onContentChanged();
Log.e("onContetnChanged", "fadsfass");
}
#Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
Log.e("onDestroy", "fadsfass");
}
#Override
public void onDetachedFromWindow() {
// TODO Auto-generated method stub
super.onDetachedFromWindow();
Log.e("onDetachedFromWindow", "fadsfass");
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
Log.e("onPause", "fadsfass");
}
#Override
protected void onRestart() {
// TODO Auto-generated method stub
super.onRestart();
Log.e("onRestart", "fadsfass");
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
Log.e("onResume", "fadsfass");
}
#Override
protected void onStart() {
// TODO Auto-generated method stub
super.onStart();
Log.e("onStart", "fadsfass");
}
#Override
protected void onStop() {
// TODO Auto-generated method stub
super.onStop();
Log.e("onStop", "fadsfass");
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.newcounteractivity_layout);
Log.e("onCreate", "mActivity equals NULL");
inputNameFirst = (EditText) findViewById(R.id.createFirstName);
inputNameLast = (EditText) findViewById(R.id.createLastName);
inputAdresse = (EditText) findViewById(R.id.createAdresse);
inputCounterID = (EditText) findViewById(R.id.createCounterID);
inputCounterValue = (EditText) findViewById(R.id.createCounterValue);
inputDescription = (EditText) findViewById(R.id.createDescription);
registerErrorMsg = (TextView) findViewById(R.id.create_error);
btnCreate = (Button) findViewById(R.id.btnCreate);
btnCancel = (Button) findViewById(R.id.btnCancel);
btnTakeImg = (Button) findViewById(R.id.btnImage);
counterImgView = (ImageView) findViewById(R.id.counterImgView);
existsDamage = (CheckBox) findViewById(R.id.createDamageExists);
//REGISTER BUTTON CLICK EVENTS
btnCreate.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//new DoBackgroundTask(NewCounterActivity.this).execute();
//CounterUser data to submit
nameFirst = inputNameFirst.getText().toString().trim();
nameLast = inputNameLast.getText().toString().trim();
adresse = inputAdresse.getText().toString().trim();
counterID = inputCounterID.getText().toString().trim();
counterValue = inputCounterValue.getText().toString().trim();
countDescript = inputDescription.getText().toString().trim();
existsDmg = Integer.toString((existsDamage.isChecked()) ? 1 : 0);
// create LocationTracker class object
gps = new LocationTracker(NewCounterActivity.this);
if(!gps.canGetLocation()){
gps.stopUsingGPS();
gps.showSettingsAlert();
//Ovo se mozda treba i izbaciti
gps.getLocation();
}
else{
processInput();
}
}
});
btnCancel.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent returnIntent = new Intent();
setResult(RESULT_CANCELED, returnIntent);
finish();
}
});
btnTakeImg.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if(isIntentAvailable(NewCounterActivity.this, MediaStore.ACTION_IMAGE_CAPTURE)){
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(takePictureIntent,2);
}
else {
Toast.makeText(NewCounterActivity.this, "No Camera Available", Toast.LENGTH_SHORT).show();
}
}
});
}
/************************************************************************************************
* Methods used in this class
* */
public void processInput(){
//Get current Longitude and Latitude
longitude = Double.toString(gps.getLongitude());
latitude = Double.toString(gps.getLatitude());
//Na kraju iskljuci location updatese - ne moze na emulatru jer ja emit coordinate preko DDMS... a kad emit on mora biti ukljucen da bi primio
//gps.stopUsingGPS();
Toast.makeText(getApplicationContext(), "Your Location is - \nLat: " + longitude + "\nLong: " + latitude, Toast.LENGTH_LONG).show();
if (!nameFirst.equals("") && !nameLast.equals("") && !adresse.equals("") && !counterID.equals("") && !counterValue.equals("")
&& counterBitmap != null ){
new DoBackgroundTask(NewCounterActivity.this).execute();
}
else{
// Not all fields are filled
registerErrorMsg.setText("Not all fields are filled");
}
}
//Method to check whether an app can handle your intent
public boolean isIntentAvailable(Context context, String action) {
final PackageManager packageManager = context.getPackageManager();
final Intent intent = new Intent(action);
List<ResolveInfo> list = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
return list.size() > 0;
}
/**************************************************************************************************
*
* When the calling activity, Activity #1, resumes after having called another activity, Activity #2, using startActivityForResult,
* the method onActivityResult in Activity #1 is called BEFORE onResume.
* This is important to know if you are instantiating your SQLite Database objects from within onResume in Activity #1. If so, you will also need to instantiate the object from within onActivityResult,
* when returning from Activity #2.
*
* startActivityForResult() is asynchronous. It can feel synchronous to the user since the UI will change and your calling activity will be paused
* (your onPause() method will be called).
*/
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, data);
Log.e("onActivityResult", "fadsfass");
if (requestCode == 2) {
if(resultCode == RESULT_OK){
Bundle extras = data.getExtras();
recievedBitmap = (Bitmap) extras.get("data");
}
if (resultCode == RESULT_CANCELED) {
Toast.makeText(NewCounterActivity.this, "No Image Taken", Toast.LENGTH_SHORT).show();
}
}
}
/**
* Koristim onWindowFocusChanged jer kad se vratim na Activity 1 onda dodje do potpunog recreate Activitija i getWidth()/height() ne mogu dobiti
* ni u jednom od lifecicle methoda - naime ide start onCreate,...onActivityResult(), onResume() - u onactivityResult izvadim bitmap i pohranim ga u receivedBitmap
* te kad getWidth() postane dostupan system invoke ovu dole methodu. :D
*/
#Override
public void onWindowFocusChanged(boolean hasFocus){
if(recievedBitmap != null){
targetW=counterImgView.getWidth();
targetH=counterImgView.getHeight();
Log.e("onWindowFocusChanged", "fadsfass" + " " + targetW + " " + targetH);
// http://stackoverflow.com/questions/4837715/how-to-resize-a-bitmap-in-android
// http://sunil-android.blogspot.com/2013/03/resize-bitmap-bitmapcreatescaledbitmap.html
// Scale or resize Bitmap to ImageView dimensions
counterBitmap = Bitmap.createScaledBitmap(recievedBitmap, targetW, targetH, false);
/**
* Canvas: trying to use a recycled bitmap android.graphics - This exception occurs when you try to recycle a bitmap which is already recycled.
* http://androdevvision.blogspot.com/2011/10/solution-for-out-of-memory-error-and.html
*/
if(recievedBitmap != null && !recievedBitmap.isRecycled()){
recievedBitmap.recycle();
recievedBitmap = null;
}
counterImgView.setImageBitmap(counterBitmap);
}
}
/************************************************************************************************
* Background AsyncTask to create new counterUser - https://github.com/callorico/CustomAsyncTask - najbolje radi
* new DoBackgroundTask(NewCounterActivity.this).execute();
* */
private static class DoBackgroundTask extends CustomAsyncTask<Void, Integer, JSONObject> {
private static final String TAG = "DoBackgroundTask";
private ProgressDialog mProgress;
private int mCurrProgress;
private NewCounterActivity myActivity = null;
public DoBackgroundTask(NewCounterActivity activity) {
super(activity);
}
#Override
protected void onPreExecute() {
super.onPreExecute();
showProgressDialog();
}
#Override
protected void onActivityDetached() {
if (mProgress != null) {
mProgress.dismiss();
mProgress = null;
}
}
#Override
protected void onActivityAttached() {
showProgressDialog();
}
private void showProgressDialog() {
mProgress = new ProgressDialog(mActivity);
mProgress.setProgressStyle(ProgressDialog.STYLE_SPINNER);
mProgress.setIndeterminate(true);
mProgress.setMessage(" Saljem na server... ");
mProgress.setCancelable(true);
mProgress.setOnCancelListener(new OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
cancel(true);
}
});
mProgress.show();
mProgress.setProgress(mCurrProgress);
}
#Override
protected JSONObject doInBackground(Void... params) {
//so you need to either pass an instance of the outer class to the inner class method (or its constructor) as a parameter,
//or create it inside the method.
JSONObject json = null;
if(mActivity != null){
myActivity = (NewCounterActivity) mActivity;
//Prepare counterBitmap as String
ByteArrayOutputStream stream = new ByteArrayOutputStream();
//Write a compressed version of the bitmap to the specified output stream.
myActivity.counterBitmap.compress(Bitmap.CompressFormat.JPEG, 90, stream);
byte [] b_array = stream.toByteArray();
String bitmapString = Base64.encodeBytes(b_array);
//Get workerId from logged worker
Functions workerFunction = new Functions();
DatabaseHandler db = new DatabaseHandler(mActivity);
String workerID = db.retrieveWorker().get("workerId");
if(myActivity != null){
//Get JsonObject from Functions.java
json = workerFunction.newCounterUser(myActivity.counterID, myActivity.counterValue, myActivity.adresse, myActivity.nameFirst, myActivity.nameLast, bitmapString, myActivity.existsDmg, myActivity.countDescript, workerID, myActivity.longitude, myActivity.latitude);
}
}
return json;
}
#Override
protected void onPostExecute(JSONObject jsonObject) {
super.onPostExecute(jsonObject);
if (mActivity != null) {
mProgress.dismiss();
try {
if (jsonObject.getString(KEY_SUCCESS) != null) {
myActivity.registerErrorMsg.setText("");
String res = jsonObject.getString(KEY_SUCCESS);
if(Integer.parseInt(res) == 1){
// counterUser successfully registered
Toast.makeText(mActivity, "New counterUser is created", Toast.LENGTH_LONG).show();
// Return back to MainActivity
Intent returnIntent = new Intent();
returnIntent.putExtra("result",jsonObject.toString());
mActivity.setResult(RESULT_OK,returnIntent);
// Close all views before launching MainActivity
returnIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
mActivity.finish();
}else{
// Error in registration
myActivity.registerErrorMsg.setText("Error occured in registration");
}
}
} catch (JSONException e) {
Log.e("Error","NO Json at all");
e.printStackTrace();
}
} else {
Log.d(TAG, "AsyncTask finished while no Activity was attached.");
}
}
}
Same issues on call to recreate(), when activity has been updated it get onPause after onResume. Tested on emulator, bug exists on Marshallow and below.
This is my fix
private static boolean isRecreate = false;
private void reCreateActivity() {
isRecreate = true;
recreate();
}
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if(isRecreate) {
isRecreate = false;
runOnUiThread(new Runnable() {
#Override
public void run() {
onResume();
}
});
}
}
I don't know if that's correct, but it works.
EDIT
Best solution to avoid this issues, call recreate in postDelayed with 0 delayMillis
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
recreate();
}
}, 0);
It is only normal, that strange code produces strange behavior ...
replace this line:
((MyApplicationClass) getApplication()).detach(this);
with this line:
super.onSaveInstanceState(outState);

IntentService runs through a list, which can be reordered concurrently via onHandleIntent

I am using IntentService to download 200 large JPGs from a list. While this is loading, the user can skip through the not-loaded JPGs and load JPG #156 for example, but after it is loaded, it should continue loading the rest. So it's like a Lazy Loader... but it continues when it's idle.
I previously used onHandleIntent and put a loop from #1 to #200... which obviously doesn't work when I try to send another IntentService call for JPG #156. So the call to #156 only happens after onHandleIntent is done with #200.
I then changed it so onHandleIntent reorders request #156 to be at the top of the list, then requests the top of the list (and downloads the JPG), then removes it from the list. It then calls the IntentService again, which sounds rather risky from a recursive/stack overflow kinda way. It works sometimes and I can see file #156 being put first... sometimes.
Is there a better way to do this? A way I could think of would be to run it all through a database.
EDIT: This is what I have come up with:
code
public class PBQDownloader extends IntentService {
int currentWeight = 0;
PriorityBlockingQueue<WeightedAsset> pbQueue = new PriorityBlockingQueue<WeightedAsset>(100, new CompareWeightedAsset());
public PBQDownloader() {
super("PBQDownloader");
}
public PBQDownloader(String name) {
super(name);
}
#Override
protected void onHandleIntent(Intent intent) {
String downloadUrl = "-NULL-";
Bundle extras = intent.getExtras();
if (extras!=null) {
downloadUrl = extras.getString("url");
Log.d("onHandleIntent 1.1", "asked to download: " + downloadUrl);
} else {
Log.d("onHandleIntent 1.2", "no URL sent so let's start queueing everything");
int MAX = 10;
for (int i = 1; i <= MAX; i++) {
// should read URLs from list
WeightedAsset waToAdd = new WeightedAsset("url: " + i, MAX - i);
if (pbQueue.contains(waToAdd)) {
Log.d("onStartCommand 1", downloadUrl + " already exists, so we are removing it and adding it back with a new priority");
pbQueue.remove(waToAdd);
}
pbQueue.put(waToAdd);
}
currentWeight = MAX + 1;
}
while (!pbQueue.isEmpty()) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
}
WeightedAsset waToProcess = pbQueue.poll();
Log.d("onHandleIntent 2 DOWNLOADED", waToProcess.url);
}
Log.d("onHandleIntent 99", "finished all IntentService calls");
}
#Override
public int onStartCommand(Intent intent, int a, int b) {
super.onStartCommand(intent, a, b);
currentWeight++;
String downloadUrl = "-NULL-";
Bundle extras = intent.getExtras();
if (extras!=null) downloadUrl = extras.getString("url");
Log.d("onStartCommand 0", "download: " + downloadUrl + " with current weight: " + currentWeight);
WeightedAsset waToAdd = new WeightedAsset(downloadUrl, currentWeight);
if (pbQueue.contains(waToAdd)) {
Log.d("onStartCommand 1", downloadUrl + " already exists, so we are removing it and adding it back with a new priority");
pbQueue.remove(waToAdd);
}
pbQueue.put(waToAdd);
return 0;
}
private class CompareWeightedAsset implements Comparator<WeightedAsset> {
#Override
public int compare(WeightedAsset a, WeightedAsset b) {
if (a.weight < b.weight) return 1;
if (a.weight > b.weight) return -1;
return 0;
}
}
private class WeightedAsset {
String url;
int weight;
public WeightedAsset(String u, int w) {
url = u;
weight = w;
}
}
}
code
Then I have this Activity:
code
public class HelloPBQ extends Activity {
int sCount = 10;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button tv01 = (Button) findViewById(R.id.tv01);
Button tv02 = (Button) findViewById(R.id.tv02);
Button tv03 = (Button) findViewById(R.id.tv03);
tv01.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
doPBQ();
}
});
tv02.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
doInitPBQ();
}
});
tv03.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
sCount = 0;
}
});
}
private void doInitPBQ() {
Intent intent = new Intent(getApplicationContext(), PBQDownloader.class);
//intent.putExtra("url", "url: " + sCount);
startService(intent);
}
private void doPBQ() {
sCount++;
Intent intent = new Intent(getApplicationContext(), PBQDownloader.class);
intent.putExtra("url", "url: " + sCount);
startService(intent);
}
}
code
Now the messy bit is that I have to keep an ever-increasing counter that runs the risk of going out of int bounds (WeightedAsset.weight) - is there a way to programmatically add to the queue and have it automatically be the head of the queue? I tried to replace WeightedAsset with a String, but it didn't poll() as I wanted, as a FIFO instead of a LIFO stack.
Here's how I'd try it first:
Step #1: Have the IntentService hold onto a PriorityBlockingQueue.
Step #2: Have onHandleIntent() iterate over the PriorityBlockingQueue, downloading each file in turn as it gets popped off the queue.
Step #3: Have onStartCommand() see if the command is the "kick off all downloads" command (in which case, chain to the superclass). If, instead, it's the "prioritize this download" command, re-prioritize that entry in the PriorityBlockingQueue, so it'll be picked up next by onHandleIntent() when the current download is finishing.

Categories

Resources