Search code examples
javaandroidalarmmanager

Notifications works without following the AlarmManager


I create two different daily notifications. Both will run at a different given time. The second notification will get some data from API, checking if the data from that API match today's date, and display it.

The first notification runs every time i set the Alarms on (I've created the settings to turn the notification on or off), but it won't run at the times given.

The other one even won't run the BroadcastReceiver class even I've already set the Alarm on.

Here's my code

MainActivity.java

public static void setAlarmDaily(Context context){
    Calendar calendar = Calendar.getInstance();
    calendar.set(Calendar.HOUR_OF_DAY, 7);
    calendar.set(Calendar.MINUTE, 0);
    calendar.set(Calendar.SECOND,0);
    Intent intent = new Intent(context, NotifyService.class);
    intent.putExtra(EXTRA_TYPE, DAILY_REQUEST_CODE);
    AlarmManager alarmManager = (AlarmManager)context.getSystemService(ALARM_SERVICE);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(context,100,intent,PendingIntent.FLAG_UPDATE_CURRENT);

    if(alarmManager != null){
        alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY,pendingIntent);
    }
}

public static void setAlarmRelease(Context context){
    Intent intent = new Intent(context, NotifyService.class);
    intent.putExtra(EXTRA_TYPE, LATEST_REQUEST_CODE);
    AlarmManager alarmManager1 = (AlarmManager)context.getSystemService(ALARM_SERVICE);
    PendingIntent pendingIntent1 = PendingIntent.getBroadcast(context,101,intent,PendingIntent.FLAG_UPDATE_CURRENT);

    Calendar calendar1 = Calendar.getInstance();
    calendar1.set(Calendar.HOUR_OF_DAY, 8);
    calendar1.set(Calendar.MINUTE, 0);
    calendar1.set(Calendar.SECOND,0);

    if(alarmManager1 != null){
        alarmManager1.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar1.getTimeInMillis(), AlarmManager.INTERVAL_DAY,pendingIntent1);
    }
}

NotifyService.java

@Override
public void onReceive(final Context context, Intent intent) {
    int type = intent.getIntExtra(EXTRA_TYPE, 101);

    if(type==100){
        showNotificationDaily(context);
    }else {
        final PendingResult pendingResult = goAsync();
        Thread thread = new Thread(){
            public void run(){
                AsyncHttpClient client = new AsyncHttpClient();
                client.get(url, new AsyncHttpResponseHandler() {
                    @Override
                    public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
                        try {
                            ArrayList<Movie> listMov = null;
                            String result = new String(responseBody);
                            JSONObject responseObject = new JSONObject(result);
                            JSONArray results = responseObject.getJSONArray("results");

                            for (int i = 0; i < results.length(); i++) {
                                int id = results.getJSONObject(i).getInt("id");
                                String title = results.getJSONObject(i).getString("title");
                                String releaseDate = results.getJSONObject(i).getString("release_date");

                                Movie mov = new Movie();
                                mov.setId(id);
                                mov.setTitle(title);
                                mov.setReleaseDate(releaseDate);
                                listMov.add(mov);
                            }
                            listMovie = listMov;
                            pendingResult.finish();
                        }catch (Exception e){
                            e.printStackTrace();
                        }
                    }
                    @Override
                    public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {

                    }
                });
            }
        };
        thread.start();

        ArrayList<Movie> movies = listMovie;
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
        Date date = new Date();
        String now = dateFormat.format(date);
        for(Movie movieItem : movies){
            if(movieItem.getReleaseDate().equals(now)){
                showNotificationRelease(context, movieItem.getId(), movieItem.getTitle());
                Log.d(TAG,movieItem.getReleaseDate());
            }
        }
    }
}

public void showNotificationRelease(Context context, int id, String title){
    Uri sound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);

    NotificationManager notificationManager2 = (NotificationManager)context.getSystemService(context.NOTIFICATION_SERVICE);
    Intent i = new Intent(context, DetailActivity.class);
    Movie movie = new Movie();
    movie.setId(id);
    movie.setTitle(title);
    movie.setType("movie");
    i.putExtra(DetailActivity.EXTRA_DETAIL,movie);
    i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    PendingIntent pIntent2 = PendingIntent.getActivity(context, 101, i, PendingIntent.FLAG_UPDATE_CURRENT);

    Notification.Builder notification2 = new Notification.Builder(context)
            .setContentIntent(pIntent2)
            .setContentTitle(context.getString(R.string.release_now_string))
            .setContentText(title + context.getString(R.string.has_release_string))
            .setSmallIcon(R.drawable.ic_live_tv_black_24dp)
            .setSound(sound)
            .setAutoCancel(true);

    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
        NotificationChannel dailyNotificationChannel = new NotificationChannel("101",
                "Latest",
                NotificationManager.IMPORTANCE_DEFAULT);

        dailyNotificationChannel.enableVibration(true);
        dailyNotificationChannel.setVibrationPattern(new long[]{1000, 1000, 1000, 1000, 1000});

        notification2.setChannelId("100");

        if(notificationManager2 != null){
            notificationManager2.createNotificationChannel(dailyNotificationChannel);
        }
    }

    if(notificationManager2 != null){
        notificationManager2.notify(101, notification2.build());
    }
}

public void showNotificationDaily(Context context){
    Uri sound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);

    NotificationManager notificationManager = (NotificationManager)context.getSystemService(context.NOTIFICATION_SERVICE);
    Intent i = new Intent(context, MainActivity.class);
    i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    PendingIntent pIntent = PendingIntent.getActivity(context, 100, i, PendingIntent.FLAG_UPDATE_CURRENT);

    Notification.Builder notification = new Notification.Builder(context)
            .setContentIntent(pIntent)
            .setContentTitle(context.getString(R.string.good_morning_string))
            .setContentText(context.getString(R.string.check_app_string))
            .setSmallIcon(R.drawable.ic_movie_black_24dp)
            .setSound(sound)
            .setAutoCancel(true);

    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
        NotificationChannel dailyNotificationChannel = new NotificationChannel("100",
                "Daily",
                NotificationManager.IMPORTANCE_DEFAULT);

        dailyNotificationChannel.enableVibration(true);
        dailyNotificationChannel.setVibrationPattern(new long[]{1000, 1000, 1000, 1000, 1000});

        notification.setChannelId("100");

        if(notificationManager != null){
            notificationManager.createNotificationChannel(dailyNotificationChannel);
        }
    }

    if(notificationManager != null){
        notificationManager.notify(100, notification.build());
    }
}

Manifest

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.moviecatalogue">

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.SET_ALARM" />
<uses-permission android:name="android.permission.WAKE_LOCK"/>

<permission
    android:name="com.dicoding.mynotesapp.READ_DATABASE"
    android:protectionLevel="normal" />
<permission
    android:name="com.dicoding.mynotesapp.WRITE_DATABASE"
    android:protectionLevel="normal" />

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <receiver android:name=".widget.ImageBannerWidget">
        <intent-filter>
            <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
        </intent-filter>

        <meta-data
            android:name="android.appwidget.provider"
            android:resource="@xml/image_banner_widget_info" />
    </receiver>

    <activity android:name=".activity.SettingsActivity">
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value=".activity.MainActivity" />
    </activity>
    <activity android:name=".activity.DetailActivity" />
    <activity
        android:name=".activity.MainActivity"
        android:configChanges="keyboardHidden|orientation|screenSize"
        android:label="@string/app_name">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <receiver android:name=".service.NotifyService" />
    <service
        android:name="com.example.moviecatalogue.widget.StackWidgetService"
        android:permission="android.permission.BIND_REMOTEVIEWS" />
    <provider
        android:name=".provider.FavoriteProvider"
        android:authorities="com.example.moviecatalogue"
        android:exported="true"
        android:readPermission="com.example.moviecatalogue.READ_DATABASE"
        android:writePermission="com.example.moviecatalogue.WRITE_DATABASE" />
</application>

I have no idea what was wrong with my code. I really need help on this.


Solution

  • Try changing the

    alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP,
         calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY,pendingIntent);
    

    to

     long dateTime = calendar.getTimeInMillis();
     if (dateTime <= System.currentTimeMillis()) {
         time = dateTime + 24 * 3600 * 1000;
     } 
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            alarmManager.setWindow(AlarmManager.RTC_WAKEUP, dateTime ,
                    AlarmManager.INTERVAL_DAY, pendingIntent);
        } else {
            alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, dateTime , 
                    AlarmManager.INTERVAL_DAY, pendingIntent);
        }
    

    If you read the Android doc related to AlarmManager

    Beginning with API 19 (Build.VERSION_CODES.KITKAT) alarm delivery is inexact: the OS will shift alarms in order to minimize wakeups and battery use. There are new APIs to support applications which need strict delivery guarantees; see setWindow(int, long, long, android.app.PendingIntent) and setExact(int, long, android.app.PendingIntent). Applications whose targetSdkVersion is earlier than API 19 will continue to see the previous behavior in which all alarms are delivered exactly when requested.

    Edit:

    I would suggest calling your setAlarmDaily and setAlarmRelease method also inside your broadcastReceiver once their respective tasks are completed. and Change the method to have alarm one time. like this:

    long dateTime = calendar.getTimeInMillis();
     if (dateTime <= System.currentTimeMillis()) {
         time = dateTime + 24 * 3600 * 1000;
     } 
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            //alarmManager.setExact(AlarmManager.RTC_WAKEUP, dateTime, pendingIntent); // not suggested
            // 15 mins of window to call the alarm and have battery optimization
            long windowMillis = 15 * 60 * 1000L;
            alarmManager.setWindow(AlarmManager.RTC_WAKEUP, dateTime ,
                    windowMillis, pendingIntent);
        } else {
            alarmManager.set(AlarmManager.RTC_WAKEUP, dateTime, pendingIntent);
        }