0

I'm an artist and I'm working on an installation with a couple Android smartphones. I'm not an expert in Java/Android programming. I'm just learning by doing and stackoverflow is very helpful. I'm using different devices with different Android versions (2.3-4.4). The devices are constantly powered via usb. The app should run only during opening hours of an exhibition and resort automatically the next day. For scheduling I'm using the AlarmManager. Currently I have problems with the automatic restart on some of the devices, on others it work as expected.

Here are some snippets important form the scheduling:

In the AndroidManifest.xml I have the following permissions set:

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

Among others the WAKE_LOCK permission is set.

onCreate starts with:

    @Override
public void onCreate(final Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_start);
    pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
    if (android.os.Build.VERSION.SDK_INT > 12) {
        if (pm != null) {
            wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK| PowerManager.ACQUIRE_CAUSES_WAKEUP
                    | PowerManager.ON_AFTER_RELEASE, "MyWakeLock");
        }
    }else {
        // unlock screen and switch screen back light on
        // for Android 2.3 - disable for higher Versions
        KeyguardManager km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
        final KeyguardManager.KeyguardLock kl;
        if (km != null) {
            kl = km.newKeyguardLock("MyKeyguardLock");
            kl.disableKeyguard();
        }
        if (pm != null) {
            wakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK| PowerManager.ACQUIRE_CAUSES_WAKEUP
                    | PowerManager.ON_AFTER_RELEASE, "MyWakeLock");
        }
    }
    wakeLock.acquire();
    Thread.setDefaultUncaughtExceptionHandler(new MyExceptionHandler(this));

PowerManager.ACQUIRE_CAUSES_WAKEUP is used, which to my understanding should put the screen on irrespectively of it's state.

In onDestroy I'm using:

        PendingIntent pendingIntent = PendingIntent.getActivity(MyApplication.getInstance().getBaseContext(),0,intent,PendingIntent.FLAG_ONE_SHOT );

        AlarmManager alarmManager = (AlarmManager) MyApplication.getInstance().getBaseContext().getSystemService(Context.ALARM_SERVICE);

        if (alarmManager != null) {
            alarmManager.set(AlarmManager.RTC_WAKEUP , System.currentTimeMillis()+delayInMillis,pendingIntent);
            Date date = new Date(System.currentTimeMillis()+delayInMillis);
            SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy ' 'HH:mm:ss.SSS");
            Log.i("** restart at **",dateFormat.format(date));
        }

This snippet is executed when finish() is called because of 'exhibition closing time reached'. As said, this works on most of the devices. On those devices, on which the app seems not to restart automatically, the app starts as soon as the screen is put on e.g. by pressing the power button or disconnecting usb (e.g. for connecting the laptop to read the logcat.) In the logcat I find something like (LG P-875 Android 4.1.3 should start at 14:00:xx)

03-25 14:00:53.516 677-748/? I/ActivityManager: START {flg=0x14000004 cmp=eu.karin_daum.daum.reality/.Start (has extras) u=0} from pid -1
03-25 14:00:53.546 677-748/? I/ActivityManager: Start proc eu.karin_daum.daum.reality for activity eu.karin_daum.daum.reality/.Start: pid=31324 uid=10099 gids={3003, 1015, 1028}

To me, this looks o.k., however the PowerManager did not react. In this example, the PowerManager reacted at the moment when I disconnected usb to connect my laptop some minutes later:

03-25 14:04:13.986 677-691/? D/PowerManagerService: userActivity mLastEventTime=201702573 time=201861160 mUserActivityAllowed=true mUserState=0x0 mWakeLockState=0x0 mProximitySensorActive=false timeoutOverride=-1 force=false
03-25 14:04:13.986 677-691/? D/PowerManagerService: setPowerState: mPowerState=0x0 newState=0x7 noChangeLights=false reason=2
03-25 14:04:13.986 677-691/? D/PowerManagerService: setPowerState: mPowerState=0 newState=7 noChangeLights=false
03-25 14:04:13.996 677-691/? D/PowerManagerService: setTimeoutLocked now=201861160 timeoutOverride=-1 nextState=3 when=201862660
03-25 14:04:14.006 677-747/? D/PowerManagerService: Perflock acquired: 7, 1
03-25 14:04:14.006 677-750/? D/PowerManagerService: offMask=0x0 dimMask=0x0 onMask=0x0 difference=0x1 realDifference=0x0 forceState=0x1
03-25 14:04:14.096 677-1038/? D/PowerManagerService: pid=31324 tag=MyWakeLock mAcquireCausesWakeupTime=201861278 diffTime=149932030
03-25 14:04:14.096 677-1038/? D/PowerManagerService: setPowerState: mPowerState=0x7 newState=0x7 noChangeLights=false reason=3

In the second but last line the request which I send in onCreate seems to be treated (tag=MyWakeLock)

During writing I just realise that the PowerManager did react automatically in the next test but only with a delay of about 10 minutes w.r.t. the AlarmManager action.

What am I doing wrong? Do I have to release the WakeLock in onDestroy? Is there a solution to the problem?

TheArtist
  • 1
  • 3

1 Answers1

0

Problem solved. There have been two reasons why it was not working as I expected on all devices:

  1. I was following the proposal made in several threads using PendingIntent.getActivity to start the activity directly instead of using a BroadcastReceiver instead. Apparently doing so would not guarantee to get control on the screen. After reading again the information on the Android Developer pages I implemented a BroadcastReceiver:

    public class StartupReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if(intent!=null){
            PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
    
            PowerManager.WakeLock wl;
            if (android.os.Build.VERSION.SDK_INT < 13) {
                wl = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP
                    | PowerManager.ON_AFTER_RELEASE, "**StartupReceiver**");
                KeyguardManager km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
                final KeyguardManager.KeyguardLock kl;
                if (km != null) {
                    kl = km.newKeyguardLock("MyKeyguardLock");
                    kl.disableKeyguard();
                }
    
            } else {wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP
                | PowerManager.ON_AFTER_RELEASE, "**StartupReceiver**");
            }
            wl.acquire();
    
    
            Intent i = new Intent(context, Start.class);
            i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(i);
            wl.release();
        }
    }}
    

    This works correctly on all devices with SDK<19

  2. In order to get it also working on SDK=19 I had to change alarmManager.set to alarmManager.setExact, i.e.

        Intent intent1 = new Intent(this,StartupReceiver.class);
        PendingIntent pendingIntent1 = PendingIntent.getBroadcast(MyApplication.getInstance().getBaseContext(),0,intent1,PendingIntent.FLAG_ONE_SHOT);
        AlarmManager alarmManager = (AlarmManager) MyApplication.getInstance().getBaseContext().getSystemService(Context.ALARM_SERVICE);
    
        if (alarmManager != null) {
            if(android.os.Build.VERSION.SDK_INT<19) {
                alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + delayInMillis, pendingIntent1);
            }else{
                alarmManager.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + delayInMillis, pendingIntent1);
    
            }
            Date date = new Date(System.currentTimeMillis()+delayInMillis);
            SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy ' 'HH:mm:ss.SSS");
            Log.i("** restart at **",dateFormat.format(date));
        }
    

These changes solved the problem

TheArtist
  • 1
  • 3