/*
* Copyright (C) 2014 AChep@xda <ynkr.wang@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.bullmobi.message.services;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.PowerManager;
import android.os.SystemClock;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.telephony.TelephonyManager;
import android.util.Log;
import com.bullmobi.message.Config;
import com.bullmobi.message.Presenter;
import com.bullmobi.message.R;
import com.bullmobi.message.services.switches.InactiveTimeSwitch;
import com.bullmobi.message.services.switches.NoNotifiesSwitch;
import com.bullmobi.message.utils.tasks.RunningTasks;
import com.bullmobi.base.content.ConfigBase;
import com.bullmobi.base.utils.PackageUtils;
import com.bullmobi.base.utils.power.PowerUtils;
import static com.bullmobi.base.Build.DEBUG;
/**
* Created by Artem on 16.02.14.
*
* @author Artem Chepurnoy
*/
public class KeyguardService extends SwitchService {
private static final String TAG = "KeyguardService";
public static boolean isActive = false;
private String mPackageName;
/**
* Starts or stops this service as required by settings and device's state.
*/
public static void handleState(Context context) {
Config config = Config.getInstance();
boolean onlyWhileChargingOption = !config.isEnabledOnlyWhileCharging()
|| PowerUtils.isPlugged(context);
if (config.isEnabled()
&& config.isKeyguardEnabled()
&& onlyWhileChargingOption) {
BathService.startService(context, KeyguardService.class);
} else {
BathService.stopService(context, KeyguardService.class);
}
}
private static final int ACTIVITY_LAUNCH_MAX_TIME = 1000;
private ActivityMonitorThread mActivityMonitorThread;
private PowerManager mPowerManager;
private final Presenter mPresenter = Presenter.getInstance();
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
TelephonyManager ts = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
final boolean isCall = ts.getCallState() != TelephonyManager.CALL_STATE_IDLE;
switch (intent.getAction()) {
case Intent.ACTION_SCREEN_ON:
String activityName = null;
long activityChangeTime = 0;
if (mActivityMonitorThread != null) {
//noinspection SynchronizeOnNonFinalField
synchronized (mActivityMonitorThread) {
mActivityMonitorThread.monitor();
activityName = mActivityMonitorThread.topActivityName;
activityChangeTime = mActivityMonitorThread.topActivityTime;
}
}
stopMonitorThread();
long now = SystemClock.elapsedRealtime();
boolean becauseOfActivityLaunch =
now - activityChangeTime < ACTIVITY_LAUNCH_MAX_TIME
&& activityName != null
&& !activityName.startsWith(mPackageName);
if (DEBUG) Log.d(TAG, "Screen is on: is_call=" + isCall +
" activity_flag=" + becauseOfActivityLaunch);
if (isCall) {
return;
}
if (becauseOfActivityLaunch) {
// Finish EasyNotification activity so it won't shown
// after exiting from newly launched one.
mPresenter.kill();
} else startGui(); // Normal launch
break;
case Intent.ACTION_SCREEN_OFF:
if (!isCall) startGuiGhost(); // Ghost launch
startMonitorThread();
break;
}
}
};
private void startGuiGhost() {
startGui();
}
private void startGui() {
Presenter.getInstance().tryStartGuiCauseKeyguard(getContext());
}
@NonNull
@Override
public Switch[] onBuildSwitches() {
Config config = Config.getInstance();
ConfigBase.Option noNotifies = config.getOption(Config.KEY_KEYGUARD_WITHOUT_NOTIFICATIONS);
ConfigBase.Option respectIt = config.getOption(Config.KEY_KEYGUARD_RESPECT_INACTIVE_TIME);
return new Switch[]{
new NoNotifiesSwitch(getContext(), this, noNotifies, true),
new InactiveTimeSwitch(getContext(), this, respectIt),
};
}
@NonNull
@Override
public String getLabel() {
return getContext().getString(R.string.service_bath_keyguard);
}
@Override
public void onStart(@Nullable Object... objects) {
Context context = getContext();
mPackageName = PackageUtils.getName(context);
mPowerManager = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_SCREEN_ON);
intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY - 1); // highest priority
context.registerReceiver(mReceiver, intentFilter);
if (!PowerUtils.isScreenOn(mPowerManager)) {
// Make sure the app is launched
startGuiGhost();
}
isActive = true;
}
@Override
public void onStop(@Nullable Object... objects) {
Context context = getContext();
context.unregisterReceiver(mReceiver);
stopMonitorThread();
if (!PowerUtils.isScreenOn(mPowerManager)) {
// Make sure that the app is not
// waiting in the shade.
mPresenter.kill();
}
isActive = false;
}
private void startMonitorThread() {
stopMonitorThread();
mActivityMonitorThread = new ActivityMonitorThread(getContext());
mActivityMonitorThread.start();
}
private void stopMonitorThread() {
if (mActivityMonitorThread == null) {
return; // Nothing to stop
}
mActivityMonitorThread.running = false;
mActivityMonitorThread.interrupt();
mActivityMonitorThread = null;
}
/**
* Thread that monitors current top activity.
* This is needed to prevent launching EasyNotification above any other
* activity which launched with
* {@link android.view.WindowManager.LayoutParams#FLAG_TURN_SCREEN_ON} flag.
*/
private static class ActivityMonitorThread extends Thread {
private static final long MONITORING_PERIOD = 15 * 60 * 1000; // 15 min.
public volatile long topActivityTime;
public volatile String topActivityName;
public volatile boolean running = true;
private final Context mContext;
public ActivityMonitorThread(@NonNull Context context) {
mContext = context;
}
@Override
public void run() {
super.run();
try {
while (running) {
monitor();
Thread.sleep(MONITORING_PERIOD);
}
} catch (InterruptedException e) { /* unused */ }
}
/**
* Checks what activity is the latest.
*/
public void monitor() {
synchronized (this) {
String topActivity = RunningTasks.getInstance().getRunningTasksTop(mContext);
if (topActivity != null && !topActivity.equals(topActivityName)) {
// Update time if it's not first try.
if (topActivityName != null) {
topActivityTime = SystemClock.elapsedRealtime();
}
topActivityName = topActivity;
if (DEBUG) Log.d(TAG, "Current top activity is " + topActivityName);
}
}
}
}
}