Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: How to check email at a specific time with AlarmManager?

I need to print all my incoming email at 9AM every morning. Here is what I tried

The email part works fine. I am able to connect to email and print them all. The problem comes when I introduce the Alarm Manager. When I run it, nothing happens. It just hangs

MainActivity.java

import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Properties; 
import javax.mail.*;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public void checkEmail(View view) {
        Log.d("test", "accessing gmail");

        Calendar cur_cal = new GregorianCalendar();
        cur_cal.setTimeInMillis(System.currentTimeMillis());//set the current time and date for this calendar

        Calendar cal = new GregorianCalendar();
        cal.add(Calendar.DAY_OF_YEAR, cur_cal.get(Calendar.DAY_OF_YEAR));
        cal.set(Calendar.HOUR_OF_DAY, 9);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, cur_cal.get(Calendar.SECOND));
        cal.set(Calendar.MILLISECOND, cur_cal.get(Calendar.MILLISECOND));
        cal.set(Calendar.DATE, cur_cal.get(Calendar.DATE));
        cal.set(Calendar.MONTH, cur_cal.get(Calendar.MONTH));


        // create an Intent 
        Intent intentAlarm = new Intent(this, AlarmReceiver.class);
        PendingIntent pi = PendingIntent.getService(this, 0, intentAlarm, 0);

        // create the object
        AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

        //set the alarm for 9 AM 
        alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 1000 * 5, pi);

        Toast.makeText(this, "Alarm Scheduled for 9 AM", Toast.LENGTH_LONG).show();

    }


}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.admin.myapplication.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:textSize="24sp"
        android:layout_height="wrap_content"
        android:text="Email Checker"
        android:id="@+id/textView2" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="New Button"
        android:id="@+id/button"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="152dp"
        android:onClick="checkEmail"/>


</RelativeLayout>

AlarmReceiver.java (UPDATED CLASS)

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.SmsManager;
import android.util.Log;
import android.widget.Toast;



public class AlarmReceiver extends BroadcastReceiver
{
    @Override
    public void onReceive(Context context, Intent intent)
    {
         Intent i = new Intent(context, AsyncTaskActvity.class);
    i.putExtra("foo", "bar");
    context.startService(i);
        Log.d("test", "async");
        Toast.makeText(context, "Alarm Triggered", Toast.LENGTH_LONG).show();
    }

}

AsyncTaskActvity.java

package com.example.admin.myapplication;

import android.os.AsyncTask;
import android.util.Log;
import java.util.Properties;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Store;

public class AsyncTaskActvity extends AsyncTask {


    @Override
    protected Object doInBackground(Object[] params) {

        computerUp();

        return null;


    }

    protected boolean computerUp () {



        try {

            Properties props = java.lang.System.getProperties();
            props.setProperty("mail.store.protocol", "imaps");
            Session session = Session.getDefaultInstance(props, null);
            Store store = session.getStore("imaps");
            store.connect("imap.gmail.com", "[email protected]", "mypassword");
            Session s = Session.getInstance(props);


            Message[] msgs;


            Folder inbox = store.getFolder("Inbox");
            inbox.open(Folder.READ_ONLY);
            msgs = inbox.getMessages();

            for (int i = 0; i < msgs.length; i++) {
                msgs[i].getSubject();
                Log.d("test", msgs[i].getSubject());
            }

        } catch (Exception e) {
            Log.e(e.getClass().getName(), e.getMessage(), e);
        }

        return true;
    }


} 

When I run it, nothing happens. What am I doing wrong?

like image 560
john Avatar asked Sep 29 '16 09:09

john


People also ask

How AlarmManager works in Android?

AlarmManager is a bridge between application and Android system alarm service. It can send a broadcast to your app (which can be completely terminated by user) at a scheduled time and your app can then perform any task accordingly.

What is Android permission SCHEDULE EXACT alarm?

What is this permission? The new exact alarm permission ( SCHEDULE_EXACT_ALARM ) was created to save system resources. Alarms that must be executed in an exact time may be triggered when the phone is on power-saving mode or Doze, making the app consumes more battery than it should.

How to make alarm in Android studio?

Navigate to the app > res > layout > activity_main. xml and add the below code to that file. In this file, we have added two items 'TimePicker' and 'ToggleButton'. TimePicker is used to capture the alarm time and ToggleButton is added to set the alarm on or off.


2 Answers

First of all, if you want to launch some code inside Android device you have to use this:

  1. AlarmManager which launches BroadcastReceiver
  2. use WakeupBroadcastReceiver to wake up your device.
  3. Use stay-in-wakeup state of Android device while executing the code.
  4. Do not forget to recharge after restarting your device.
  5. YOU HAVE A PROBLEM WHILE STARTING ASYNCTASK !!!
  6. You have incorrect alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 1000 * 5, pi); implementation. this string mean:"execute my code each 5 seconds. Start it is now!". This is not 9AM time;)

So, try this:

  1. To charge AlarmManager at specific time:
Intent intent = new Intent(BRWakeup.INTENT_FILTER) ;

        PendingIntent pi =  PendingIntent.getBroadcast(ctx, intentalarm, intent, PendingIntent.FLAG_CANCEL_CURRENT);
        int currentapiVersion = android.os.Build.VERSION.SDK_INT;
        if (currentapiVersion < android.os.Build.VERSION_CODES.KITKAT){
          am.set(wakeup?AlarmManager.RTC_WAKEUP:AlarmManager.RTC, nexttime, pi);
        } else if (currentapiVersion >= android.os.Build.VERSION_CODES.LOLLIPOP) 
          if (currentapiVersion < android.os.Build.VERSION_CODES.M) {
              am.setExact(AlarmManager.RTC_WAKEUP, nexttime, pi);
          } else {
                  am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, nexttime, pi);
          }
        }

where ctx - current Context class (parent Class for Activity and Service). For example, in Activity class this is getContext() or getActivity(). nexttime - time to lauch the receiver. For example, long nexttime = System.getCurrentTimeMillis();, AlarmManager am = (AlarmManager) ctx.getSystemService(Activity.ALARM_SERVICE); , intentalarm - is a some unique number to detect this launch event in future. It may be any number your want but the constant in your app. For example, final int intentalarm = 22344;

  1. To launch service from BroadcastReceiver:
public class BRWakeup extends WakefulBroadcastReceiver {
  public static final String INTENT_FILTER = "com.example.BRWakeup";
  @Override
  public void onReceive(Context ctx, Intent intent) {
      // TODO Auto-generated method stub
      OWakeLocker.acquire(ctx, 0);
      ComponentName comp = new ComponentName(ctx.getPackageName(),
                SService.class.getName());
      startWakefulService(ctx, intent.setComponent(comp));
  }

}
  1. OWakeLocker is my own class which stores all launched services to save their lifes.
public class OWakeLocker {
    private static PowerManager.WakeLock[] wakeLocks = new PowerManager.WakeLock[1];//Services count

    @SuppressWarnings("deprecation")
  public static void acquire(Context ctx, int index) {
      WakeLock wakeLock = wakeLocks[index];
        if (wakeLock != null) wakeLock.release();

        PowerManager pm = (PowerManager) ctx.getSystemService(Context.POWER_SERVICE);
          wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK |
                  PowerManager.ACQUIRE_CAUSES_WAKEUP |
                  PowerManager.ON_AFTER_RELEASE, _.APPNAME + Integer.toString(index));
        if (wakeLock != null && wakeLock.isHeld()){
          wakeLock.acquire();
        }
    }

    public static void release(int index) {
      WakeLock wakeLock = wakeLocks[index];
        if (wakeLock != null) 
          wakeLock.release();
          wakeLock = null;
    }
}
  1. Use this service to execute your code:
public class SService extends Service {

@Override
    public void onCreate() {
      OWakeLocker.acquire(this, 0);
      super.onCreate();
}
@Override
  public void onDestroy() {
      super.onDestroy();
      OWakeLocker.release(_.indexNOTS_TAT);
  }
@Override
  public int onStartCommand(Intent intent, int flags, int startId) {
      //your code to start AsyncTask

AsyncTaskActvity atask = new AsyncTaskActvity();
    atsk.execute();
}
}
  1. To calculate good 9AM time you have to use this code: time and date for this calendar
     Calendar cal = Calendar.getInstance();
boolean iftoday = cal.get(Calendar.HOUR_OF_DAY) < 9;

//to set the time as exact
        cal.set(Calendar.HOUR_OF_DAY, 9);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);

        if (!iftoday) {
           cal.add(Calendar.DATE, 1);  
        }
        long nexttime = cal.getTimeInMillis();//this is the correct next time.
  1. Use setExactAndAllowWhileIdle instead of setRepeating... . And recharge AlarmManager at SService.onDestroy() method using the same code as in the Activity

  2. Edit AndroidManifest.xml

<receiver android:name="com.example.BRWakeup"
          android:exported="false">
          <intent-filter>
              <action android:name="com.example.BRWakeup"/>
          </intent-filter>
      </receiver>
<service android:name="com.example.SService"></service>
like image 200
Vyacheslav Avatar answered Nov 14 '22 08:11

Vyacheslav


Use Intent-Service with Broadcast Receiver.

Follow below link with example :

Background Service

  public class MyAlarmReceiver extends BroadcastReceiver {
   public static final int REQUEST_CODE = 12345;
   public static final String ACTION = "com.codepath.example.servicesdemo.alarm";
 // Triggered by the Alarm periodically (starts the service to run task)
    @Override
    public void onReceive(Context context, Intent intent) {
     Intent i = new Intent(context, MyTestService.class);
     i.putExtra("foo", "bar");
     context.startService(i);
    }
}
like image 31
Chirag Arora Avatar answered Nov 14 '22 08:11

Chirag Arora