0

I have an app that utilises both the camera and a BLE MIDI device. Because it uses a camera it employs a wakelock to keep the screen active when the activity is running.

I also added some logcat messages on the activity's onPause, onResume and onUserLeaveHint methods. The result is the following:

07-15 21:55:15.422 31551-31551/uk.co.mxklabs.pianoeye V/mxklogcat: CameraActivity [onUserLeaveHint]
07-15 21:55:15.540 31551-31551/uk.co.mxklabs.pianoeye V/mxklogcat: CameraActivity [wakelock release]
07-15 21:55:15.541 31551-31551/uk.co.mxklabs.pianoeye V/mxklogcat: CameraActivity [onPause]
07-15 21:55:15.597 31551-31551/uk.co.mxklabs.pianoeye V/mxklogcat: CameraActivity [onResume]
07-15 21:56:16.701 31551-31551/uk.co.mxklabs.pianoeye V/mxklogcat: CameraActivity [onUserLeaveHint]
07-15 21:56:16.931 31551-31551/uk.co.mxklabs.pianoeye V/mxklogcat: CameraActivity [wakelock release]
07-15 21:56:16.933 31551-31551/uk.co.mxklabs.pianoeye V/mxklogcat: CameraActivity [onPause]
07-15 21:56:17.017 31551-31551/uk.co.mxklabs.pianoeye V/mxklogcat: CameraActivity [onResume]
07-15 21:57:18.118 31551-31551/uk.co.mxklabs.pianoeye V/mxklogcat: CameraActivity [onUserLeaveHint]
07-15 21:57:18.245 31551-31551/uk.co.mxklabs.pianoeye V/mxklogcat: CameraActivity [wakelock release]
07-15 21:57:18.246 31551-31551/uk.co.mxklabs.pianoeye V/mxklogcat: CameraActivity [onPause]
07-15 21:57:18.307 31551-31551/uk.co.mxklabs.pianoeye V/mxklogcat: CameraActivity [onResume]
07-15 21:58:55.196 31551-31551/uk.co.mxklabs.pianoeye V/mxklogcat: CameraActivity [onUserLeaveHint]
07-15 21:58:55.331 31551-31551/uk.co.mxklabs.pianoeye V/mxklogcat: CameraActivity [wakelock release]
07-15 21:58:55.332 31551-31551/uk.co.mxklabs.pianoeye V/mxklogcat: CameraActivity [onPause]
07-15 21:58:55.388 31551-31551/uk.co.mxklabs.pianoeye V/mxklogcat: CameraActivity [onResume]

For reasons I don't understand, something is causing my activity to pause every minute and then immediately resume.

Although onUseLeaveHint is called prior to onPause the phone is not being touched during this period, it is by itself on my desk with the screen on.

The above is problematic because I have BLE resources and am recording a MIDI file. If I were to close and re-open the MIDI device this often I am concerned it would lead to timing issues in the recording.

Is this normal? If not, any ideas why this is happening?

Here's my Activity:

package uk.co.mxklabs.pianoeye;

import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.os.PowerManager;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;

import uk.co.mxklabs.androidlib.music.midi.IMidiEventListener;
import uk.co.mxklabs.androidlib.music.midi.SimpleMidiEventAdapter;

public class CameraActivity extends Activity
        implements SharedPreferences.OnSharedPreferenceChangeListener
{

    private static final String TAG = "mxklogcat";

    private PowerManager.WakeLock m_wakeLock;
    private SimpleMidiEventAdapter m_midiAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_camera);
        //getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        if (null == savedInstanceState)
        {
            getFragmentManager().beginTransaction()
                    .replace(R.id.container, Camera2VideoFragment.newInstance())
                    .commit();
        }

        PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
        m_wakeLock = powerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, TAG);

        m_midiAdapter = new SimpleMidiEventAdapter(this.getApplicationContext(), "");
        //m_midiAdapter.addMidiEventListener(mSurfaceView);
        m_midiAdapter.addMidiEventListener(new IMidiEventListener()
        {
            @Override
            public void noteOn(int channel, int midiNote, int velocity)
            {
                Log.v(TAG, "Note " + Integer.toString(midiNote) + " on, velocity " + Integer.toString(velocity) + "!");
            }

            @Override
            public void noteOff(int channel, int midiNote, int velocity)
            {
                Log.v(TAG, "Note " + Integer.toString(midiNote) + " off!");
            }
        });
    }

    @Override
    public void onResume()
    {
        Log.v(TAG, "CameraActivity [onResume]");
        super.onResume();
        m_midiAdapter.onResume();

        Log.v(TAG, "WakeLock [wakelock acquire]");
        m_wakeLock.acquire();

        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
        prefs.registerOnSharedPreferenceChangeListener(this);
        //processVideoOverlayTransparencyValue(prefs);
        processMidiDevice(prefs);
    }

    @Override
    protected void onUserLeaveHint()
    {
        Log.v(TAG, "CameraActivity [onUserLeaveHint]");
        super.onUserLeaveHint();
    }

    @Override
    public void onPause()
    {
        Log.v(TAG, "CameraActivity [wakelock release]");
        m_wakeLock.release();

        Log.v(TAG, "CameraActivity [onPause]");
        m_midiAdapter.onPause();
        super.onPause();

        // TODO: Make consistent pause/onPause.
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState)
    {
        Log.v(TAG, "CameraActivity [onCreate]");
        super.onCreate(savedInstanceState, persistentState);
    }

    @Override
    protected void onStart()
    {
        Log.v(TAG, "CameraActivity [onStart]");
        super.onStart();
    }

    @Override
    protected void onRestart()
    {
        Log.v(TAG, "CameraActivity [onRestart]");
        super.onRestart();
    }

    @Override
    protected void onStop()
    {
        Log.v(TAG, "CameraActivity [onStop]");
        super.onStop();
    }

    @Override
    protected void onDestroy()
    {
        Log.v(TAG, "CameraActivity [onDestroy]");
        super.onDestroy();
    }

    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)
    {
        if (key == "pref_bluetooth_midi_select_device")
        {
            processMidiDevice(sharedPreferences);
        }

        Log.v(TAG, "Preference \"" + key + "\" changed");
    }

    public void processMidiDevice(SharedPreferences sharedPreferences)
    {
        final String MIDI_DEVICE_ID = sharedPreferences.getString("pref_bluetooth_midi_select_device", "");

        m_midiAdapter.changeMidiDeviceId(MIDI_DEVICE_ID);
    }

    public void handleSettingsButtonClick(View v)
    {
        Log.v(TAG, "setting_button clicked");

        Intent intent = new Intent(this, SettingsActivity.class);
        //myIntent.putExtra("key", value); //Optional parameters
        this.startActivity(intent);

    }

}

Here's my Manifest:

<?xml version="1.0" encoding="utf-8"?><!--
 Copyright 2014 The Android Open Source Project

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="uk.co.mxklabs.pianospy"
    android:versionCode="1"
    android:versionName="1.0">

    <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->

    <uses-permission android:name="android.permission.CAMERA"/>
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

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

    <application android:allowBackup="true"
        android:label="@string/app_name"
        android:icon="@drawable/ic_launcher"
        android:theme="@style/Theme.AppCompat.Light">

        <activity android:name=".CameraActivity"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".SettingsActivity"
            android:label="@string/title_activity_settings"
            android:parentActivityName=".MainActivity">
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value="uk.co.mxklabs.pianoeye.MainActivity" />
        </activity>

    </application>
</manifest>

I don't expect my activity to pause and immediately resume every minute or so.

EDIT: I tried alternatives to wakelock (e.g. FLAG_KEEP_SCREEN_ON) and it behaves the same:

07-16 19:53:26.799 15583-15583/uk.co.mxklabs.pianoeye V/mxklogcat: CameraActivity [onUserLeaveHint]
07-16 19:53:26.934 15583-15583/uk.co.mxklabs.pianoeye V/mxklogcat: CameraActivity [onPause]
07-16 19:53:26.997 15583-15583/uk.co.mxklabs.pianoeye V/mxklogcat: CameraActivity [onResume]
07-16 19:54:28.111 15583-15583/uk.co.mxklabs.pianoeye V/mxklogcat: CameraActivity [onUserLeaveHint]
07-16 19:54:28.224 15583-15583/uk.co.mxklabs.pianoeye V/mxklogcat: CameraActivity [onPause]
07-16 19:54:28.291 15583-15583/uk.co.mxklabs.pianoeye V/mxklogcat: CameraActivity [onResume]
07-16 19:55:29.369 15583-15583/uk.co.mxklabs.pianoeye V/mxklogcat: CameraActivity [onUserLeaveHint]
07-16 19:55:29.491 15583-15583/uk.co.mxklabs.pianoeye V/mxklogcat: CameraActivity [onPause]
07-16 19:55:29.560 15583-15583/uk.co.mxklabs.pianoeye V/mxklogcat: CameraActivity [onResume]
07-16 19:56:30.647 15583-15583/uk.co.mxklabs.pianoeye V/mxklogcat: CameraActivity [onUserLeaveHint]
07-16 19:56:30.771 15583-15583/uk.co.mxklabs.pianoeye V/mxklogcat: CameraActivity [onPause
07-16 19:56:30.847 15583-15583/uk.co.mxklabs.pianoeye V/mxklogcat: CameraActivity [onResume]

EDIT: Here's a minimal example that exhibits the same behaviour and uses FLAG_KEEP_SCREEN_ON:

package uk.co.mxklabs.testapp.myapplication;

import android.os.PersistableBundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.WindowManager;

public class MainActivity extends AppCompatActivity
{

    private static final String TAG = "mxklogcat";

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    }

    @Override
    public void onResume()
    {
        Log.v(TAG, "MainActivity [onResume]");
        super.onResume();
    }

    @Override
    protected void onUserLeaveHint()
    {
        Log.v(TAG, "MainActivity [onUserLeaveHint]");
        super.onUserLeaveHint();
    }

    @Override
    public void onPause()
    {
        Log.v(TAG, "MainActivity [onPause]");
        super.onPause();
    }
}

SOLVED: I noticed this problem didn't happen on another phone and figured it might be another app causing this problem. I uninstalled pretty well half the apps on my phone and this problem went away.

mxk
  • 67
  • 4

1 Answers1

0

You are doing what the documentation has told you directly not to do.

Creating and holding wake locks can have a dramatic impact on the host device's battery 
life. Thus you should use wake locks only when strictly necessary and hold them 
for as short a time as possible. For example, you should never need to use a wake lock 
in an activity. As described above, if you want to keep the screen on in your activity, 
use FLAG_KEEP_SCREEN_ON.

You should be utilizing the FLAG_KEEP_SCREEN_ON and moving your CPU intensive work to a background service. Use BroadcastReciever to notify and finish your recording work.

jnewkirk
  • 391
  • 1
  • 2
  • 13
  • I tried FLAG_KEEP_SCREEN_ON and it had the same end result. Is it normal to get a onPause/onResume every minute with this setup or is there something fishy going on? – mxk Jul 16 '19 at 06:21
  • I'm not sure what the repercussions of using Wakelock in an activity are, but it tells you not to do so. This _could_ be causing issues with the lifecycle. I also don't know what your `SimpleMidiEventAdapter` is doing. – jnewkirk Jul 16 '19 at 15:17
  • While I agree using the wakelock in the Activity is wrong (and I'll remove it from the Activity) the result with FLAG_KEEP_SCREEN_ON is very similar, so I don't think the wakelock is the *cause* of this behaviour. So my question is still the same, would you expect onPause/onResume to get called every minute? – mxk Jul 16 '19 at 18:59
  • @mxk Looking at this [explanation](https://stackoverflow.com/a/25474853/653839), I would assume that because you are keeping the screen on, the lifecycles are called because you are forcing the screen to stay on. I would maybe use a flag to manage when to properly call your expected logic. – jnewkirk Jul 17 '19 at 19:43