/*
* MaxLock, an Xposed applock module for Android
* Copyright (C) 2014-2016 Max Rumpf alias Maxr1998
*
* 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 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 de.Maxr1998.xposed.maxlock.no_xposed;
import android.accessibilityservice.AccessibilityService;
import android.annotation.TargetApi;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.Build;
import android.provider.Settings;
import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityWindowInfo;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import de.Maxr1998.xposed.maxlock.Common;
import de.Maxr1998.xposed.maxlock.MLImplementation;
import de.Maxr1998.xposed.maxlock.ui.LockActivity;
import de.Maxr1998.xposed.maxlock.util.AppLockHelpers;
import de.Maxr1998.xposed.maxlock.util.MLPreferences;
import static de.Maxr1998.xposed.maxlock.util.AppLockHelpers.CLOSE_OBJECT_KEY;
import static de.Maxr1998.xposed.maxlock.util.AppLockHelpers.IMOD_RESET_ON_SCREEN_OFF;
import static de.Maxr1998.xposed.maxlock.util.AppLockHelpers.PACKAGE_HISTORY_ARRAY_KEY;
import static de.Maxr1998.xposed.maxlock.util.AppLockHelpers.PROCESS_HISTORY_ARRAY_KEY;
import static de.Maxr1998.xposed.maxlock.util.AppLockHelpers.addToHistory;
import static de.Maxr1998.xposed.maxlock.util.AppLockHelpers.close;
import static de.Maxr1998.xposed.maxlock.util.AppLockHelpers.getDefault;
import static de.Maxr1998.xposed.maxlock.util.AppLockHelpers.pass;
import static de.Maxr1998.xposed.maxlock.util.AppLockHelpers.readFile;
import static de.Maxr1998.xposed.maxlock.util.AppLockHelpers.writeFile;
public class AppLockService extends AccessibilityService {
public static final String TAG = "AppLockService";
private SharedPreferences prefs;
private SharedPreferences prefsApps;
private BroadcastReceiver screenOffReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
try {
if (prefsApps.getBoolean(IMOD_RESET_ON_SCREEN_OFF, false)) {
writeFile(getDefault());
Log.d(TAG, "Screen turned off, locked apps.");
} else {
writeFile(readFile()
.put(PROCESS_HISTORY_ARRAY_KEY, new JSONArray())
.put(PACKAGE_HISTORY_ARRAY_KEY, new JSONArray())
.put(CLOSE_OBJECT_KEY, new JSONObject()));
}
} catch (JSONException e) {
Log.e(TAG, "Error in screenOffReceiver", e);
}
}
};
@Override
public void onCreate() {
super.onCreate();
prefs = MLPreferences.getPreferences(this);
prefsApps = MLPreferences.getPrefsApps(this);
registerReceiver(screenOffReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));
}
@Override
protected void onServiceConnected() {
Log.i(TAG, "Started up");
try {
String currentPackage = getRootInActiveWindow().getPackageName().toString();
if (prefsApps.getBoolean(currentPackage, false)) {
handlePackage(currentPackage);
}
} catch (Throwable t) {
Log.e(TAG, "Error in handling startup poll", t);
}
}
@Override
public void onAccessibilityEvent(AccessibilityEvent accessibilityEvent) {
// If service is not disabled yet
if (MLImplementation.getImplementation(prefs) == MLImplementation.DEFAULT) {
stopSelf();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
disableSelf();
}
return;
}
final String packageName = String.valueOf(accessibilityEvent.getPackageName());
if (packageName.equals("null") ||
accessibilityEvent.getEventType() != AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED ||
((Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && getWindowType(accessibilityEvent) != AccessibilityWindowInfo.TYPE_APPLICATION) ||
packageName.equals("android") || packageName.matches("com\\.(google\\.)?android\\.systemui") ||
Settings.Secure.getString(getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD).startsWith(packageName))) {
return;
}
Log.d(TAG, "Window state changed: " + packageName);
try {
if (prefsApps.getBoolean(packageName, false)) {
handlePackage(packageName);
} else {
writeFile(addToHistory(-1, packageName, readFile()));
}
} catch (Throwable t) {
Log.e(TAG, "Error in handling event", t);
}
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private int getWindowType(AccessibilityEvent accessibilityEvent) {
for (AccessibilityWindowInfo info : getWindows()) {
if (accessibilityEvent.getWindowId() == info.getId()) {
return info.getType();
}
}
return AccessibilityWindowInfo.TYPE_APPLICATION;
}
private void handlePackage(String packageName) throws Throwable {
JSONObject history = AppLockHelpers.readFile();
if (close(history, packageName)) {
performGlobalAction(GLOBAL_ACTION_HOME);
return;
}
if (pass(-1, packageName, null, history, prefsApps)) {
return;
}
Log.d(TAG, "Show lockscreen: " + packageName);
Intent i = new Intent(this, LockActivity.class)
.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_FROM_BACKGROUND | Intent.FLAG_ACTIVITY_SINGLE_TOP)
.putExtra(Common.INTENT_EXTRAS_NAMES, new String[]{packageName, null});
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N)
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
}
@Override
public void onInterrupt() {
}
@Override
public void onDestroy() {
unregisterReceiver(screenOffReceiver);
performGlobalAction(GLOBAL_ACTION_HOME);
super.onDestroy();
}
}