/* * Copyright (C) 2014 AChep@xda <artemchep@gmail.com> * * 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 2 * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ package com.achep.acdisplay.services; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.Handler; import android.os.SystemClock; import android.support.annotation.NonNull; import android.util.Log; import com.achep.acdisplay.Config; import com.achep.acdisplay.R; import com.achep.base.AppHeap; import com.achep.base.utils.FileUtils; import com.achep.base.utils.power.PowerUtils; import java.io.File; import java.util.LinkedList; import static com.achep.base.Build.DEBUG; /** * Created by achep on 24.08.14. */ public class SensorsDumpService extends BathService.ChildService implements SensorEventListener { private static final String TAG = "SensorsDumpService"; private static final char DIVIDER = ';'; private static final char NEW_LINE = '\n'; private static final int MAX_SIZE = 2500; private SensorManager mSensorManager; private final int[] mSensorTypes = new int[]{ Sensor.TYPE_GYROSCOPE, Sensor.TYPE_ACCELEROMETER, }; private final LinkedList<Event> mEventList = new LinkedList<>(); private static class Event { long timestamp; float[] values; int sensor; } private Handler mHandler = new Handler(); private Receiver mReceiver = new Receiver(); private class Receiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { switch (intent.getAction()) { case Intent.ACTION_SCREEN_ON: startListening(); // Stop listening after some minutes to keep battery. mHandler.postDelayed(new Runnable() { @Override public void run() { synchronized (mEventList) { stopListening(); mEventList.clear(); } } }, 120 * 1000); break; case Intent.ACTION_SCREEN_OFF: stopListening(); dropToStorage(); break; } } } /** * Starts or stops this service as required by settings and device's state. */ public static void handleState(@NonNull Context context) { Config config = Config.getInstance(); boolean onlyWhileChangingOption = !config.isEnabledOnlyWhileCharging() || PowerUtils.isPlugged(context); if (config.isEnabled() && config.isDevSensorsDumpEnabled() && onlyWhileChangingOption) { BathService.startService(context, SensorsDumpService.class); } else { BathService.stopService(context, SensorsDumpService.class); } } @Override public void onCreate() { Context context = getContext(); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_SCREEN_ON); intentFilter.addAction(Intent.ACTION_SCREEN_OFF); intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY - 1); context.registerReceiver(mReceiver, intentFilter); mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); } @Override public void onDestroy() { getContext().unregisterReceiver(mReceiver); stopListening(); // Watch for the leaks AppHeap.getRefWatcher().watch(this); } @Override public String getLabel() { return getContext().getString(R.string.service_bath_active_mode_dump); } private void startListening() { for (int type : mSensorTypes) { Sensor sensor = mSensorManager.getDefaultSensor(type); if (sensor != null) { if (DEBUG) Log.d(TAG, "Listening to " + sensor.getName() + " sensor..."); mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_GAME); } } } private void stopListening() { if (DEBUG) Log.d(TAG, "Stopping listening..."); mSensorManager.unregisterListener(this); mHandler.removeCallbacksAndMessages(null); } private void dropToStorage() { synchronized (mEventList) { if (DEBUG) Log.d(TAG, "Dumping sensors data to file..."); if (mEventList.size() == 0) { return; } StringBuilder sb = new StringBuilder(); for (Event event : mEventList) { sb.append(event.timestamp).append(DIVIDER); sb.append(event.sensor).append(DIVIDER); for (float f : event.values) sb.append(f).append(DIVIDER); sb.append(NEW_LINE); } String filename = "dump_sensors_" + SystemClock.elapsedRealtime() + ".txt"; File file = new File(getContext().getFilesDir(), filename); FileUtils.writeToFile(file, sb); mEventList.clear(); } } @Override public void onSensorChanged(SensorEvent sensorEvent) { synchronized (mEventList) { Event event = new Event(); event.timestamp = SystemClock.elapsedRealtime(); event.values = sensorEvent.values.clone(); event.sensor = sensorEvent.sensor.getType(); mEventList.add(event); int size = mEventList.size(); if (size > MAX_SIZE) { mEventList.remove(0); } } } @Override public void onAccuracyChanged(Sensor sensor, int i) { /* unused */ } }