Android Open Source - SpartanTimeLapseRecorder Background Service






From Project

Back to project page SpartanTimeLapseRecorder.

License

The source code is released under:

GNU General Public License

If you think the Android project SpartanTimeLapseRecorder listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Spartan Time Lapse Recorder - Minimalistic android time lapse recording app
 * Copyright (C) 2014  Andreas Rohner//from  w  w  w.j a v  a  2s.  c o  m
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package at.andreasrohner.spartantimelapserec;

import java.io.File;

import android.app.AlarmManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Message;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.preference.PreferenceManager;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.TaskStackBuilder;
import android.util.Log;
import android.view.Gravity;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.widget.Toast;
import at.andreasrohner.spartantimelapserec.R;
import at.andreasrohner.spartantimelapserec.data.RecSettings;
import at.andreasrohner.spartantimelapserec.recorder.Recorder;

public class BackgroundService extends Service implements
    SurfaceHolder.Callback, Handler.Callback {
  private static final String TAG = "BackgroundService";
  private static final int NOTIFICATION_ID = 95430432;
  private static boolean created;
  private SurfaceView surfaceView;
  private WakeLock wakeLock;
  private RecSettings settings;
  private Recorder recorder;
  private HandlerThread handlerThread;

  public static boolean isCreated() {
    return created;
  }

  private void createNotification(int id) {
    NotificationCompat.Builder builder = new NotificationCompat.Builder(
        this).setSmallIcon(settings.getNotificationIcon())
        .setContentTitle(getString(R.string.app_name))
        .setContentText(getString(R.string.notification_content_text));

    // Creates an explicit intent for an Activity in your app
    Intent resultIntent = new Intent(this, MainActivity.class);
    // The stack builder object will contain an artificial back stack for
    // the started Activity. This ensures that navigating backward from the
    // Activity leads out of your application to the Home screen.
    TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
    // Adds the back stack for the Intent (but not the Intent itself)
    stackBuilder.addParentStack(MainActivity.class);
    // Adds the Intent that starts the Activity to the top of the stack
    stackBuilder.addNextIntent(resultIntent);
    PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0,
        PendingIntent.FLAG_UPDATE_CURRENT);
    builder.setContentIntent(resultPendingIntent);

    Notification notification = builder.build();
    // Start foreground service to avoid unexpected kill
    startForeground(id, notification);
  }

  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
    if (intent != null
        && intent.getBooleanExtra("powerSavingCallback", false)
        && recorder != null && wakeLock != null && settings != null
        && settings.shouldUsePowerSaveMode() && handlerThread != null
        && handlerThread.isAlive()) {
      wakeLock.acquire();
      Handler handler = new Handler(handlerThread.getLooper());
      handler.post(new Runnable() {
        @Override
        public void run() {
          recorder.start();
        }
      });
    }
    return super.onStartCommand(intent, flags, startId);
  }

  @SuppressWarnings("deprecation")
  @Override
  public void onCreate() {
    created = true;

    settings = new RecSettings();
    settings.load(getApplicationContext(), PreferenceManager
        .getDefaultSharedPreferences(getApplicationContext()));

    createNotification(NOTIFICATION_ID);

    if (settings.isSchedRecEnabled()
        && settings.getSchedRecTime() > System.currentTimeMillis() + 10000) {
      AlarmManager alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
      Intent intent = new Intent(getApplicationContext(),
          ScheduleReceiver.class);
      PendingIntent alarmIntent = PendingIntent.getBroadcast(
          getApplicationContext(), 0, intent, 0);

      alarmMgr.set(AlarmManager.RTC_WAKEUP, settings.getSchedRecTime(),
          alarmIntent);

      stopSelf();
      return;
    }

    // Create new SurfaceView, set its size to 1x1, move
    // it to the top left corner and set this service as a callback
    WindowManager winMgr = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
    surfaceView = new SurfaceView(this);
    // deprecated setting, but required on Android versions prior to 3.0
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB)
      surfaceView.getHolder().setType(
          SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    surfaceView.getHolder().addCallback(this);

    LayoutParams layoutParams = new WindowManager.LayoutParams(1, 1,
        WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
        WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
        PixelFormat.TRANSLUCENT);
    layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
    winMgr.addView(surfaceView, layoutParams);

    PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
    wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
    wakeLock.setReferenceCounted(false);
    wakeLock.acquire();
  }

  @Override
  public void surfaceCreated(final SurfaceHolder surfaceHolder) {
    handlerThread = new HandlerThread("recordingVideo");
    handlerThread.start();

    Context context = getApplicationContext();
    Handler handler = new Handler(handlerThread.getLooper(), this);

    recorder = Recorder.getInstance(settings, surfaceHolder, context,
        handler, wakeLock);

    handler.post(new Runnable() {
      @Override
      public void run() {
        recorder.start();
      }
    });
  }

  @Override
  public void onDestroy() {
    created = false;
    File projectDir = null;

    final Handler handler = new Handler(handlerThread.getLooper());
    handler.post(new Runnable() {
      @Override
      public void run() {
        if (recorder != null)
          recorder.stop();
        handlerThread.quit();
      }
    });

    try {
      handlerThread.join(5000);
      if (handlerThread.isAlive()) {
        handlerThread.quit();
        handlerThread.join(2000);
      }
    } catch (Exception e) {
    }

    if (recorder != null) {
      projectDir = recorder.getOutputDir();
      recorder = null;
    }

    if (surfaceView != null) {
      WindowManager winMgr = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
      winMgr.removeView(surfaceView);
    }

    if (wakeLock != null)
      wakeLock.release();

    if (projectDir != null && projectDir.exists())
      sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,
          Uri.fromFile(projectDir)));
  }

  @Override
  public boolean handleMessage(Message m) {
    String status = m.getData().getString("status");
    String tag = m.getData().getString("tag");
    String msg = m.getData().getString("msg");

    String name = getString(R.string.app_name);

    if ("error".equals(status)) {
      Log.e(tag, "Error: " + msg);

      final Context context = getApplicationContext();
      final String text = name + " Error: " + msg;

      surfaceView.post(new Runnable() {
        @Override
        public void run() {
          Toast toast = Toast.makeText(context, text,
              Toast.LENGTH_LONG);
          toast.show();
        }
      });
    }

    stopSelf();
    return true;
  }

  @Override
  public void surfaceChanged(SurfaceHolder surfaceHolder, int format,
      int width, int height) {
  }

  @Override
  public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
  }

  @Override
  public IBinder onBind(Intent intent) {
    return null;
  }
}




Java Source Code List

at.andreasrohner.spartantimelapserec.BackgroundService.java
at.andreasrohner.spartantimelapserec.DeviceStatusReceiver.java
at.andreasrohner.spartantimelapserec.MainActivity.java
at.andreasrohner.spartantimelapserec.PowerSavingReceiver.java
at.andreasrohner.spartantimelapserec.PreviewActivity.java
at.andreasrohner.spartantimelapserec.ScheduleReceiver.java
at.andreasrohner.spartantimelapserec.SettingsActivity.java
at.andreasrohner.spartantimelapserec.SettingsCommon.java
at.andreasrohner.spartantimelapserec.SettingsFragment.java
at.andreasrohner.spartantimelapserec.data.RecMode.java
at.andreasrohner.spartantimelapserec.data.RecSettings.java
at.andreasrohner.spartantimelapserec.preference.DateTimePreference.java
at.andreasrohner.spartantimelapserec.preference.IconArrayAdapter.java
at.andreasrohner.spartantimelapserec.preference.IconListPreference.java
at.andreasrohner.spartantimelapserec.preference.NoKBEditTextPreference.java
at.andreasrohner.spartantimelapserec.preference.SeekBarPreference.java
at.andreasrohner.spartantimelapserec.recorder.ImageRecorder.java
at.andreasrohner.spartantimelapserec.recorder.PowerSavingImageRecorder.java
at.andreasrohner.spartantimelapserec.recorder.Recorder.java
at.andreasrohner.spartantimelapserec.recorder.VideoRecorder.java
at.andreasrohner.spartantimelapserec.recorder.VideoTimeLapseRecorder.java
at.andreasrohner.spartantimelapserec.sensor.CameraSettings.java
at.andreasrohner.spartantimelapserec.sensor.MuteShutter.java
at.andreasrohner.spartantimelapserec.sensor.OrientationSensor.java