1

Description

I am developing an app (for testing purposes), that every 60 seconds will save a word in a database (using SQLiteOpenHelper). I am trying to achieve that by using AlarmManager (setRepeating) + Wake Lock (PARTIAL_WAKE_LOCK). It is important that the app also runs even if the screen is black.

I tested my app for 2 days, tried several approaches but i have 1 issue which i can´t figure out. The best result i got code-wise is what i posted.

I tested the app on 2 different phones a Samsung Galaxy s6 edge and a HTC One M8. On the Samsung phone the app will run for 1-5 iterations and then die totally. On the HTC it will keep running as if the Wake Lock works as it should. An iteration in my case is my AlarmManager which make a call every 60 seconds.

Notice! The app does run as it should on the Samsung Phone, if i have the USB with charging connected, but that was expected since the CPU does not sleep then.

My Question

Am i doing something wrong if i want to achieve what my description says?

Versions

Samsung Galaxy s6 Edge Android version: 6.0.1

HTC One M8 Android version: 6.0.1

Code

AndroidManifest

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

        <activity android:name=".Repeating_activity"/>
        <receiver android:name=".Notification_receiver"/>

    </application>



</manifest>

MainActivity

package com.example.acce.dailyrepeatinglocalnotification;

import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

public class MainActivity extends AppCompatActivity  {

    private TextView text;
    String tag = "LifeCycleEvents";
    AlarmManager alarmManager;
    PendingIntent pendingIntent;
    boolean isAlarmRunning = false;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(tag, "In the onCreate() event");
        text = (TextView) findViewById(R.id.textView3);
    }


    public void startAlarm(View v) {
        Calendar calendar = Calendar.getInstance();
        Intent intent = new Intent(getApplicationContext(), Notification_receiver.class);
        pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 100, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
        alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,calendar.getTimeInMillis(),60000, pendingIntent);
        Toast.makeText(this,"Alarm started", Toast.LENGTH_SHORT).show();
        isAlarmRunning = true;
    }

    public void stopAlarm(View v) {
        if(isAlarmRunning) {
            alarmManager.cancel(pendingIntent);
            Toast.makeText(this,"Alarm stopped", Toast.LENGTH_SHORT).show();
            isAlarmRunning = false;
        } else {
            Toast.makeText(this,"No alarm running!", Toast.LENGTH_SHORT).show();
        }
    }


    public void ShowAll(View view) {
        List notificationList = new ArrayList<String>();
        DatabaseHandler db = new DatabaseHandler(this);
        notificationList = db.getAllNotifications();
        int msg = notificationList.size();
        text.setText(String.valueOf(msg));
    }
}

Notification_receiver

package com.example.acce.dailyrepeatinglocalnotification;

import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.PowerManager;
import android.support.v4.app.NotificationCompat;

public class Notification_receiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "asdasdasd");
        wl.acquire();

        DatabaseHandler db = new DatabaseHandler(context);

        db.addNotification("A new notification");

        wl.release();
    }
}

DatabaseHandler

package com.example.acce.dailyrepeatinglocalnotification;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Daniel on 01-10-2016.
 */
public class DatabaseHandler extends SQLiteOpenHelper {

    // All Static variables
    // Database Version
    private static final int DATABASE_VERSION = 1;

    // Database Name
    private static final String DATABASE_NAME = "AlarmNotifications";

    // table name
    private static final String TABLE_NAME = "notifications";

    // Table Columns names
    private static final String KEY_ID = "id";
    private static final String KEY_NAME = "name";

    public DatabaseHandler(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        String CREATE_CONTACTS_TABLE = "CREATE TABLE " + TABLE_NAME + "("
                + KEY_ID + " INTEGER PRIMARY KEY," + KEY_NAME + " TEXT)";
        db.execSQL(CREATE_CONTACTS_TABLE);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // Drop older table if existed
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);

        // Create tables again
        onCreate(db);
    }

    // add
    public void addNotification(String name) {
        SQLiteDatabase db = this.getWritableDatabase();

        ContentValues values = new ContentValues();
        values.put(KEY_NAME, name);

        db.insert(TABLE_NAME, null, values);
        db.close();
    }

    public List getAllNotifications() {
        List<String> notifcationList = new ArrayList<String>();

        String selectQuery = "SELECT * FROM " + TABLE_NAME;

        SQLiteDatabase db = this.getWritableDatabase();
        Cursor cursor = db.rawQuery(selectQuery, null);

        if(cursor.moveToFirst()) {
            do {
                notifcationList.add(cursor.getString(1)); // the name
            } while(cursor.moveToNext());
        }
        return notifcationList;
    }


}
Daniel
  • 2,002
  • 5
  • 20
  • 32
  • It is possible that Samsung tweaked Doze mode to kick in more quickly. Also, `setRepeating()` is inexact, and you are not using `WakefulBroadcastReceiver`. – CommonsWare Oct 02 '16 at 12:28
  • I did try the WakefulBroadcastReceiver, and the result is the same. So to be clear, with WakefulBroadcastReceiver the HTC ran but the Samsung did not. Also regarding the Doze mode, on my Samsung phone i have all battery saving stuff disabled (of what i can disable). – Daniel Oct 02 '16 at 15:18
  • On Android 6.0+, Doze mode is not something you can disable. You can add your app to the battery optimization whitelist (Settings > Apps > gear icon > Battery optimization, mark your app as not optimized). Bear in mind that users may not do this. If your app is for personal use, this isn't a problem, but if you are planning on distributing the app, doing something every minute is impractical on Android 6.0+. – CommonsWare Oct 02 '16 at 15:21
  • Thanks for the answer. The 60 seconds interval is just a test, the real app will be 10 minutes. Are you telling me that, if i set it t0 minutes it will work on the Samsung device if i do not set it to the whitelist ? – Daniel Oct 02 '16 at 15:44
  • 1
    If you switch from `setRepeating()` to `setAndAllowWhileIdle()` or `setExactAndAllowWhileIdle()` (doing your own repeat logic), you may have better luck. Even then, there is no guarantee that you will get control every 10 minutes -- it will be whenever the device enters into an "idle maintenance window". Now, Doze mode is not supposed to kick in until ~1 hour has elapsed; I am just guessing that the Samsung is entering it early due to manufacturer tinkering. – CommonsWare Oct 02 '16 at 16:00
  • Im amazed how people are creating an app that can repeat an action like a fitness app. I tried all of the above you said, no change. I added my app to the whitelist with your written approach. ONLY if i have the power cord attached to my samsung phone it will run. Otherwise same results as always. – Daniel Oct 02 '16 at 16:45
  • "Im amazed how people are creating an app that can repeat an action like a fitness app" -- the fitness apps that I have seen are in the foreground and use `setKeepScreenOn()` (or `android:keepScreenOn`) so the user can continue to interact with them. You are also welcome to use a foreground service, a `WakeLock`, and some in-process timer (e.g., `ScheduledExecutorService`), so long as what you are trying to do is fairly short, as you will be keeping the CPU powered on (and, eventually, Doze mode will block that as well). – CommonsWare Oct 02 '16 at 16:52
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/124749/discussion-between-daniel-and-commonsware). – Daniel Oct 02 '16 at 19:14
  • It is important that my app can still do some task while the screen is off. We can try and catch each other in a chat at some point. If you have some idea to what i can do, please provide an answer :-) And let´s discuss from there. Thanks. – Daniel Oct 02 '16 at 19:25
  • I have same problem and tested my app few days and any tips dont help me. Do you solve the problem? – AlexS Dec 26 '18 at 13:15

0 Answers0