/*
* Copyright (C) 2015 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.switches;
import android.content.Context;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import com.achep.acdisplay.services.Switch;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
/**
* Prevents {@link com.achep.acdisplay.services.SwitchService} from working
* while an phone app is calling.
*
* @author Artem Chepurnoy
*/
public final class PhoneCallSwitch extends Switch {
private static final String TAG = "PhoneCallSwitch";
@NonNull
private final CallMonitor mCallMonitor;
public PhoneCallSwitch(@NonNull Context context, @NonNull Callback callback) {
super(context, callback);
mCallMonitor = new CallMonitor(context, new CallMonitor.OnCallStateChangedListener() {
@Override
public void onCallStateChanged(int state) {
if (isActive()) {
requestActive();
} else requestInactive();
}
});
}
/**
* {@inheritDoc}
*/
@Override
public void onCreate() {
mCallMonitor.start();
}
/**
* {@inheritDoc}
*/
@Override
public void onDestroy() {
mCallMonitor.stop();
}
/**
* {@inheritDoc}
*/
@Override
public boolean isActive() {
return !mCallMonitor.isCalling();
}
/**
* @return whether if the phone is calling now
*/
public boolean isCalling() {
return mCallMonitor.isCalling();
}
/**
* @author Artem Chepurnoy
*/
private static class CallMonitor {
private boolean mStarted;
/**
* @author Artem Chepurnoy
*/
public interface OnCallStateChangedListener {
/**
* Callback invoked when device call state changes.
*/
void onCallStateChanged(int state);
}
@NonNull
private final Context mContext;
@NonNull
private final Handler mHandler;
@NonNull
private final OnCallStateChangedListener mCallback;
private Listener mListener;
private TelephonyManager mTelephonyManager;
public CallMonitor(
@NonNull Context context,
@NonNull OnCallStateChangedListener listener) {
mContext = context;
mCallback = listener;
mHandler = new Handler();
mListener = new Listener(this);
}
public void start() {
mStarted = true;
mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_CALL_STATE);
}
public void stop() {
mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_NONE);
mTelephonyManager = null;
mStarted = false;
}
/**
* @return the current call state.
* @see #isCalling()
*/
public int getCallState() {
return mListener.getCallState();
}
/**
* @return whether if the phone is calling now
* @see #getCallState()
*/
public boolean isCalling() {
final int state = getCallState();
return state == TelephonyManager.CALL_STATE_RINGING
|| state == TelephonyManager.CALL_STATE_OFFHOOK;
}
private void notifyCallStateChanged(final int state) {
mHandler.post(new Runnable() {
@Override
public void run() {
if (mStarted) mCallback.onCallStateChanged(state);
}
});
}
/**
* @author Artem Chepurnoy
*/
private static class Listener extends PhoneStateListener {
@NonNull
private final Reference<CallMonitor> mCallHandlerRef;
/**
* The current call state.
*/
private int mState;
public Listener(@NonNull CallMonitor callStateListener) {
mCallHandlerRef = new WeakReference<>(callStateListener);
mState = TelephonyManager.CALL_STATE_IDLE;
}
@Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
if (mState == state) return;
mState = state;
// Notify the call handler
CallMonitor callStateListener = mCallHandlerRef.get();
if (callStateListener != null) callStateListener.notifyCallStateChanged(state);
}
/**
* @return the current call state.
*/
public int getCallState() {
return mState;
}
}
}
}