Android Studio - Do not close app when locking phone - java

I've searched a lot on the Internet trying to find an answer for my needs, but in vain.
Here's my problem: I'm making an app that "counts time". The user press "Start" button and then go away for pretty much a long time of work on the field (2h,even more).
Then he has to come back and press the "End" button to show he have finished his job. My app then computes how long has he worked ( and some other thing I wont explain here ), and the user send the total of his work hours by mails to his superior.
Problem is :
-First my app is closed when the phone is locked and so the Start time is lost and calculations are off.
-Second : the user has to repeat the Start-End cycle many times a day, so i have a way of computing the total work hours, but again it's lost when the app is closed
So I'm opened to any idea/suggestions to solve my issues :)
Oh and I have Huawei P8 Lite for info, if that matters in anyway
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext=MainActivity.this;
mTimeListenerD.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) { //Button to set the Start time
setDebutTime();
checkEnabled();
writeToFile(sName,sTempsTravail);
}
});
mTimeListenerF.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) { //Button to set the End Time
setFinTime();
checkEnabled();
getHeureSupp(mTimeD, mTimeF);
FindSmallest(TimeRegister);
Clock();
writeToFile(sName,sTempsTravail);
readFromFile();
try {
copyFile(src,dst);
} catch (IOException e) {
e.printStackTrace();
}
Reinit();
}
});
mMail.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
sendMail();
}
}); //Send data by mail
readFromFile();
getName();
checkEnabled();
}
public Calendar setDebutTime() { // Set the Start Time
mTimeD = Calendar.getInstance();
mTimeD.getTime();
//Toast.makeText(this, mTimeD.getTime().toString(), Toast.LENGTH_SHORT).show();
sDebut = mTimeD.get(Calendar.DAY_OF_MONTH) + "/" + mTimeD.get(Calendar.MONTH) + "/" + mTimeD.get(Calendar.YEAR) + "--" + mTimeD.get(Calendar.HOUR_OF_DAY) + ":" + mTimeD.get(Calendar.MINUTE) + ":" + mTimeD.get(Calendar.SECOND);
mGetTimeDebut.setText("" + sDebut);
start=true;
notif=false;
String pathToMyAttachedFile = "/Android/data/com.example.benjii.saphir_astreinte/files/Documents/SAPHIRAgent.csv"; //A changer
File root = Environment.getExternalStorageDirectory();
File file = new File(root, pathToMyAttachedFile);
boolean deleted =file.delete();
if(!deleted){file.delete();}
return mTimeD;
}
public Calendar setFinTime() { // set the End Time
mTimeF = Calendar.getInstance();
mTimeF.getTime();
// Toast.makeText(this, mTimeF.getTime().toString(), Toast.LENGTH_SHORT).show();
sFin = mTimeF.get(Calendar.DAY_OF_MONTH) + "/" + mTimeF.get(Calendar.MONTH) + "/" + mTimeF.get(Calendar.YEAR) + "--" + mTimeF.get(Calendar.HOUR_OF_DAY) + ":" + mTimeF.get(Calendar.MINUTE) + ":" + mTimeF.get(Calendar.SECOND);
mGetTimeFin.setText("" + sFin);
start=false;
notif=true;
return mTimeF;
}
Then I have some function to do the calculations I need with the worked hours.
Once it is done I write it into a file on Internal Storage but then copy it to external storage:
public void writeToFile(String Name,String TempsTravail){ //File that'll be send by mail
try{
OutputStreamWriter StrW= new OutputStreamWriter(this.openFileOutput("SAPHIRAgent.csv", Context.MODE_PRIVATE));
src=mContext.getFilesDir().getAbsolutePath()+"/file.csv";
dst=mContext.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS).getAbsolutePath()+"/file.csv";
//Toast.makeText(this,dst,Toast.LENGTH_LONG).show();
StrW.append(Name);
StrW.append(separator);
StrW.append(sDebut);
StrW.append(separator);
StrW.append(sFin);
StrW.append(separator);
StrW.append(TempsTravail);
StrW.append("\n"+mTempsTravail);
if(cool){
StrW.append(separator);
StrW.append(sCool);
}
if(warning){
StrW.append(separator);
StrW.append(sWarning);
}
if(critical){
StrW.append(separator);
StrW.append(sCritical);
}
StrW.flush();
StrW.close();
}
catch (IOException e){
Log.e("ExceptionFile","Failed to write "+e.toString());
}
}
Then I send the file by mail:
public void sendMail(){ //SendMail function
Intent emailIntent = new Intent(Intent.ACTION_SEND);
final String[] to={"xxx#gmail.com"};
final String subj="Sortie Agent "+sName;
final String body="Voir pièce jointe";
emailIntent.setType("text/plain");
emailIntent.putExtra(Intent.EXTRA_EMAIL, to);
emailIntent.putExtra(Intent.EXTRA_SUBJECT, subj);
emailIntent.putExtra(Intent.EXTRA_TEXT, body);
File root = Environment.getExternalStorageDirectory();
String pathToMyAttachedFile = "/Android/data/com.example.myapp/files/Documents/file.csv";
File file = new File(root, pathToMyAttachedFile);
//Toast.makeText(this,"RootPath "+root.getAbsolutePath(),Toast.LENGTH_LONG).show();
if (!file.exists() || !file.canRead()) {
Toast.makeText(this,"ToastError",Toast.LENGTH_LONG).show();
return;
}
Uri uri = Uri.fromFile(file);
emailIntent.putExtra(Intent.EXTRA_STREAM, uri);
startActivity(Intent.createChooser(emailIntent, "Choisissez votre application de Mail (Gmail,Outlook...)"));
}
But as I said, my app constantly closing is such an issue to my work, I hope you have any solutions !

Activity's are designed to stop once the phone sleeps.
What you need is a background service that runs always.
https://developer.android.com/training/run-background-service/create-service.html
http://www.vogella.com/tutorials/AndroidServices/article.html

So thanks to #Matthew Shearer, I've been able to fix my issues,learn many things about services and have a fully functionnal app on all phones, but Huawei.I learnt that Huawei phones had a specific function called "Protected Apps" which gave me many problems to keep my service alive.
But there is a solution here :
"Protected Apps" setting on Huawei phones, and how to handle it
Copy paste the code, use the ifHuaweiAlert() in the onCreate() and enjoy!

Related

How to record audio from each microphone on an android phone into separate files at the same time?

In android studio I am able to create a mediaRecorder instance and record audio, I can then create an instance of a mediaRecorder with a different audio source and record audio. The problem is that I cannot have two mediaRecorders at one time (or so I think).
In addition to mediaRecorder, I have looked into using two different AudioRecord objects but it appears someone here tried that about a month ago and it does not work either. I have looked into the mediaMuxer which may be the key to this, but I am new to the concept of multiplexing and do not know how to implement something of this kind.
// not to professional standards
btnRecord.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(checkPermissionFromDevice()) {
pathsave = Environment.getExternalStorageDirectory()
.getAbsolutePath() + "/"
+ UUID.randomUUID().toString() +
"_audio_record.3gp";
setupMediaRecorder();
try {
mediaRecorder.prepare();
mediaRecorder.start();
} catch (IOException e) {
e.printStackTrace();
}
btnPlay.setEnabled(false);
btnStop.setEnabled(false);
btnStopRecord.setEnabled(true);
Toast.makeText(MainActivity.this, "Recording...",
Toast.LENGTH_SHORT).show();
}
else{
requestPermission();
}
}
});
//------------------------------------------------------------------------
btnRecord2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(checkPermissionFromDevice()) {
pathsave2 = Environment.getExternalStorageDirectory()
.getAbsolutePath() + "/"
+ UUID.randomUUID().toString() +
"_audio_record.3gp";
setupMediaRecorder2();
try {
mediaRecorder2.prepare();
mediaRecorder2.start();
} catch (IOException e) {
e.printStackTrace();
}
btnPlay2.setEnabled(false);
btnStop2.setEnabled(false);
btnStopRecord2.setEnabled(true);
Toast.makeText(MainActivity.this, "Recording...",
Toast.LENGTH_SHORT).show();
}
else{
requestPermission();
}
}
});
//-----------------------------------------------------------------------
private void setupMediaRecorder() {
mediaRecorder = new MediaRecorder();
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mediaRecorder.setAudioEncoder(MediaRecorder.OutputFormat.AMR_NB);
mediaRecorder.setOutputFile(pathsave);
}
//------------------------------------------------------------------------
private void setupMediaRecorder2() {
mediaRecorder2 = new MediaRecorder();
mediaRecorder2.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mediaRecorder2.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mediaRecorder2.setAudioEncoder(MediaRecorder.OutputFormat.AMR_NB);
mediaRecorder2.setOutputFile(pathsave2);
}
I can record, stop recording and playback both media recorders separately. When I try to record both at the same time, the app crashes. Any help would be greatly appreciated.

Android studio twitter check if user is logged in

I have followed twitter fabric log in and everything is working fine except for the part where i try to post a tweet. When i execute this following code i need to login again, so it seems like i have to check an access token or some, but i have no idea and can't find how to do that.
#Override
public void onCreate(Bundle savedInstanceState) {
//initialize facebook sdk
FacebookSdk.sdkInitialize(getActivity().getApplicationContext());
super.onCreate(savedInstanceState);
TwitterSession session = Twitter.getSessionManager().getActiveSession();
TwitterAuthToken authToken = session.getAuthToken();
String token = authToken.token;
String secret = authToken.secret;
if (token != null ) {
Log.d(TAG, "twitter token" + token);
}
if (secret != null ) {
Log.d(TAG, "twitter secret" + secret);
}
TwitterAuthConfig authConfig = new TwitterAuthConfig(TWITTER_KEY, TWITTER_SECRET);
Fabric.with(this.getActivity(), new TwitterCore(authConfig), new TweetComposer());
}
then i am using a function to post the tweet
public void TwitterSharing() {
Log.d(TAG, "Running twitter share");
Log.d(TAG, "Share on twitter 1: " + sport);
Log.d(TAG, "Share on twitter 2: " + speed);
Log.d(TAG, "Share on twitter 3: " + distance);
Log.d(TAG, "Share on twitter 4: " + date);
Log.d(TAG, "Shared image url: " + sharedImage);
TweetComposer.Builder builder = new TweetComposer.Builder(this.getActivity())
.text("just setting up my Fabric.")
.image(Uri.parse(sharedImage));
builder.show();
}
It all works but on the web page it is loading i need to login again, that should not happen but i have no idea how.
Thanks for any input.
For that, you need to make an Activity as the launcher activity. Let's call it DispatchActivity
public class DispatchActivity extends Activity{
#Override
public void onCreate(Bundle savedInstanceState){
This returns true if user is logged in.
boolean isLoggedIn = mSharedPreferences.getBoolean(PREF_KEY_TWITTER_LOGIN, false);
if (isLoggedIn){
//User is logged in, take him to your activity
Intent i = new Intent(this,yourMainActivity.class);
this.startActivity(i);
}
else{
//User is not logged in, take him to your SignIn activity
Intent i = new Intent(this,SignUp.class);
this.startActivity(i);
}
}
}
Remember to make this your launcher activity, and don't create a layout file for it.

How to handle changes from MediaSession remote volume overlay?

I am trying to implement a remote volume control. It already works to control the volume with the hardware volume keys but when I try to move the slider in the MediaSession remote volume overlay, the VolumeProviderCompat.onAdjustVolume(..) callback is not called. I also tried other callbacks like MediaSessionCompat.Callback.onMediaButtonEvent(..) or VolumeProviderCompat.onSetVolumeTo(..) but they are not called at all.
If you don't know what I mean with the "MediaSession remote volume overlay", here is a screenshot:
I created a demo project which you can download here: https://github.com/SaschaZ/VolumeProviderDemo.
Here are the related parts of my DemoActivity:
public class DemoActivity extends AppCompatActivity {
...
private Notification createNotification(#NonNull final DemoVolumeController demoVolumeController) {
Log.d(TAG, "createNotification()");
final NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setSmallIcon(R.mipmap.ic_launcher);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (session != null) {
session.release();
}
session = new MediaSessionCompat(this, "demoMediaSession");
session.setPlaybackState(new PlaybackStateCompat.Builder()
.setState(PlaybackStateCompat.STATE_PLAYING, 1, 1.0f)
.build());
session.setPlaybackToRemote(createVolumeProvider(demoVolumeController));
session.setActive(true);
}
return builder.build();
}
private VolumeProviderCompat createVolumeProvider(#NonNull final DemoVolumeController demoVolumeController) {
// I don't use this callback directly, but I need to set it or my VolumeProvider will not work. (sounds
// strange but I tried it several times)
session.setCallback(new MediaSessionCompat.Callback() {
#Override
public boolean onMediaButtonEvent(final Intent mediaButtonEvent) {
Log.d(TAG, "onMediaButtonEvent() called with: " + "mediaButtonEvent = [" + mediaButtonEvent + "]");
return super.onMediaButtonEvent(mediaButtonEvent);
}
});
return new VolumeProviderCompat(VolumeProviderCompat.VOLUME_CONTROL_RELATIVE,
100,
demoVolumeController.getVolume()) {
#Override
public void onAdjustVolume(final int direction) {
final int volume = demoVolumeController.setVolumeRelative(direction);
showVolume(volume);
Log.d(TAG, "onAdjustVolume() called with: " + "direction = [" + direction + "] - " +
"new volume=" + volume);
// Nasty hack to get sync with the volume overlay of Android. setCurrentVolume does not work :(
session.setPlaybackToRemote(createVolumeProvider(demoVolumeController));
}
};
}
...
}
Any hints?
Thank you in advance!
Using the Activity’s setVolumeControlStream method—typically within its onCreate method—
allows you to specify which audio stream should be controlled by the volume keys while the current
Activity is active:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.audioplayer);
setVolumeControlStream(AudioManager.STREAM_MUSIC);
}
You can specify any of the available audio streams, but when using the Media Player, you should
specify the STREAM_MUSIC stream to make it the focus of the volume keys.

Android - DownloadManager / BroadcastReceiver called multiple times

I am using a DownloadManager to handle a download in my application, I would like to notify the user when the download is completed.
I am using the folowing code that is working well
public void downloaddownload(View v){
View v2 = (View) v.getParent();
TextView urlView = (TextView) v2.findViewById(R.id.url);
String urlString = (String) urlView.getText().toString();
TextView artistView2 = (TextView) v2.findViewById(R.id.artist);
final String artistString = (String) artistView2.getText().toString();
TextView titleView2 = (TextView) v2.findViewById(R.id.title);
final String titleString = (String) titleView2.getText().toString();
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(urlString));
request.setDescription(titleString);
request.setTitle(artistString);
// in order for this if to run, you must use the android 3.2 to compile your app
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
}
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_MUSIC + "/folder", titleString + " - " + artistString + ".mp3");
Toast.makeText(mainContext, "Downloading " + titleString + " - " + artistString, Toast.LENGTH_SHORT).show();
// get download service and enqueue file
DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
manager.enqueue(request);
onComplete = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
Toast.makeText(mainContext, "Download \" " + titleString + " - " + artistString + "\" completed", Toast.LENGTH_LONG).show();
}
};
registerReceiver(onComplete, new IntentFilter(
DownloadManager.ACTION_DOWNLOAD_COMPLETE));
}
The problem is that the onReceive method is called for previous downloads too.
Let's say I download a.mp3, b.mp3 and c.mp3, when a.mp3 is completed I recieve a.mp3 completed, when b.mp3 is completed I recieve a.mp3 is completed, then a new toast b.mp3 is completed...
How could I prevent this? thank you.
Yo are registering a BroadcastReceiver each time you download a file. That means, the second time you download a file, you'll have two receivers registered. You should probably unregister them using unregisterReceiver() after the work is done (probably in onReceive()).
long downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0);
Query query = new Query();
query.setFilterById(downloadId);
Cursor cur = manager.query(query);
if (cur.moveToFirst()) {
int columnIndex = cur.getColumnIndex(DownloadManager.COLUMN_STATUS);
if (DownloadManager.STATUS_SUCCESSFUL == cur.getInt(columnIndex)) {
titleString=cur.getString(cur.getColumnIndex(DownloadManager.COLUMN_TITLE));}
you should use this to get your title string for individual downloads . because every download have their own id . I know Answer is too late but it may help for others in future...

how can i add multithreading or other similar function to android application?

my android application freezes for a few seconds when i try to send my database file to my remote server, is there anyway i can set this as a background thread using multithreading or another such feature?
this is the code for the dialog box that appears to ask me if i want to send
public void showYesNoBox(){
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
switch (which){
case DialogInterface.BUTTON_POSITIVE:
//Yes button clicked
SendData();
finish();//go back to the previous Activity
overridePendingTransition(R.anim.fadein, R.anim.fadeout);
break;
case DialogInterface.BUTTON_NEGATIVE:
//No button clicked
finish();//go back to the previous Activity
overridePendingTransition(R.anim.fadein, R.anim.fadeout);
break;
}
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(this, AlertDialog.THEME_HOLO_DARK);
builder.setMessage("Do you want to send the data now?");
builder.setPositiveButton("Yes", dialogClickListener);
builder.setNegativeButton("No", dialogClickListener);
builder.show();
}
and here is the code it executes when i click the "Yes" button
public void SendData() {
File path = getDatabasePath(DataBaseHelper.DATABASE_NAME);
if (path.exists())
copyDatabase(path);
}
/**
* Copy the database to the sdcard
* #param file
*/
private void copyDatabase(File file) {
SimpleDateFormat dateFormat1 = new SimpleDateFormat("ddMMyy-HHmmss");
String dateString = dateFormat1.format(new Date());
String pathdest = getDir().getAbsolutePath() + Configuration.LOST_FOLDER + "/Database/";
String pathdir = pathdest;
File dir = new File(pathdir);
if (!dir.exists())
dir.mkdirs();
String namefile = file.getName();
int pos = namefile.lastIndexOf('.');
if (pos != -1) {
String ext = namefile.substring(pos + 1);
String name = namefile.substring(0, pos - 1);
pathdest += name;
pathdest += "_" + dateString;
pathdest += ext;
} else {
pathdest += namefile;
pathdest += "_" + dateString;
}
File filedest = new File(pathdest);
try {
if (filedest.createNewFile())
copyFile(file.getAbsolutePath(), pathdest);
} catch (IOException e) {
e.printStackTrace();
}
}
any help with this problem would be greatly appreciated as while the problem doesn't prevent the user from being able to send the data it is anoying to be stuck on one screen for a few seconds while it attempts to execute the action.
while the problem doesn't prevent the user from being able to send the data it is anoying to be stuck on one screen for a few seconds while it attempts to execute the action.
You can see AsyncTask. Its for the same purposes. User need not be stuck on UI when you want to do long running processes including taking to server, doing database stuff etc. This can be done in the background using AsyncTask. There are many good tutorials out there. Just Google it. Checkout Android Background Processing with Threads, Handlers and AsyncTask - Tutorial and What arguments are passed into AsyncTask<arg1, arg2, arg3>? . Hope this helps.
I've been using asynctask for handling all the processes I want to do in the background.
AsyncTask
Use all network operations in AsyncTask
like the below example
private class UploadTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
// upload task
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}
Once created, a task is executed very simply:
new UploadTask().execute(url1, url2, url3);

Categories

Resources