/* * 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.ui.fragments; import android.app.Activity; import android.content.Context; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.Handler; import android.os.Message; import com.achep.base.ui.fragments.leakcanary.LeakWatchFragment; /** * Non-UI fragment that listens to the proximity sensor to let us know * when to turn screen off. * <p> * <b>Please note, that you must * {@link #setListener(PocketFragment.OnSleepRequestListener) initialize listener} * before attaching fragment!</b> * </p> * * @author Artem Chepurnoy * @see #setListener(PocketFragment.OnSleepRequestListener) */ public class PocketFragment extends LeakWatchFragment implements SensorEventListener { public static final String TAG = "PocketFragment"; private static final int SLEEP_DELAY = 1500; // 1.5 sec. private static final int MSG_SLEEP = 0; private SensorManager mSensorManager; private Sensor mProximitySensor; private boolean mProximityAvailable; private boolean mNear; private boolean mFirstChange; private float mMaximumRange; private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case MSG_SLEEP: if (mListener != null) { mListener.onSleepRequest(); } break; } } }; private OnSleepRequestListener mListener; /** * Interface definition for a callback to be invoked * when device has been put to the pocket. */ public interface OnSleepRequestListener { /** * Called when parent activity may go to sleep because we're * in pocket at this moment. */ boolean onSleepRequest(); } public static PocketFragment newInstance() { return new PocketFragment(); } public PocketFragment setListener(OnSleepRequestListener listener) { mListener = listener; return this; } @Override public void onAttach(Activity activity) { super.onAttach(activity); mSensorManager = (SensorManager) activity.getSystemService(Context.SENSOR_SERVICE); mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY); mProximityAvailable = mProximitySensor != null; if (mProximityAvailable) { mMaximumRange = mProximitySensor.getMaximumRange(); } } @Override public void onResume() { super.onResume(); if (mProximityAvailable) { mSensorManager.registerListener(this, mProximitySensor, SensorManager.SENSOR_DELAY_NORMAL); mFirstChange = true; mNear = false; } } @Override public void onPause() { super.onPause(); mHandler.removeCallbacksAndMessages(null); mSensorManager.unregisterListener(this); } @Override public void onDetach() { super.onDetach(); mSensorManager = null; mProximitySensor = null; } @Override public void onSensorChanged(SensorEvent event) { final float distance = event.values[0]; final boolean isNear = distance < mMaximumRange || distance < 1.0f; final boolean changed = mNear != (mNear = isNear) || mFirstChange; if (!changed) { // Well just in cause if proximity sensor is NOT always eventual. // This should not happen, but who knows... I found maximum // range buggy enough. return; } mHandler.removeCallbacksAndMessages(null); if (!isNear) { return; } mHandler.sendEmptyMessageDelayed(MSG_SLEEP, SLEEP_DELAY); } @Override public void onAccuracyChanged(Sensor sensor, int i) { /* unused */ } }