diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index bf2d2ff6d..fcfe2031f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -144,6 +144,18 @@ + + + + + + + + diff --git a/app/src/main/java/fr/neamar/kiss/forwarder/ExperienceTweaks.java b/app/src/main/java/fr/neamar/kiss/forwarder/ExperienceTweaks.java index 7f7b16bab..7bef5756b 100644 --- a/app/src/main/java/fr/neamar/kiss/forwarder/ExperienceTweaks.java +++ b/app/src/main/java/fr/neamar/kiss/forwarder/ExperienceTweaks.java @@ -1,7 +1,12 @@ package fr.neamar.kiss.forwarder; +import android.accessibilityservice.AccessibilityServiceInfo; import android.annotation.SuppressLint; +import android.app.AlertDialog; +import android.content.Context; +import android.content.Intent; import android.content.pm.ActivityInfo; +import android.content.pm.ServiceInfo; import android.os.Build; import android.os.Handler; import android.provider.Settings; @@ -9,16 +14,19 @@ import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; +import android.view.accessibility.AccessibilityManager; import android.widget.ImageView; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.List; import fr.neamar.kiss.MainActivity; import fr.neamar.kiss.R; import fr.neamar.kiss.searcher.HistorySearcher; import fr.neamar.kiss.searcher.NullSearcher; import fr.neamar.kiss.searcher.Searcher; +import fr.neamar.kiss.utils.LockAccessibilityService; // Deals with any settings in the "User Experience" setting sub-screen class ExperienceTweaks extends Forwarder { @@ -46,6 +54,7 @@ class ExperienceTweaks extends Forwarder { private View mainEmptyView; private final GestureDetector gd; + @SuppressLint("SourceLockedOrientationActivity") ExperienceTweaks(final MainActivity mainActivity) { super(mainActivity); @@ -63,14 +72,43 @@ class ExperienceTweaks extends Forwarder { gd = new GestureDetector(mainActivity, new GestureDetector.SimpleOnGestureListener() { @Override - public boolean onSingleTapUp(MotionEvent e) { - if(prefs.getBoolean("history-onclick", false)) { + public boolean onSingleTapConfirmed(MotionEvent e) { + if (prefs.getBoolean("history-onclick", false)) { doAction("display-history"); } return super.onSingleTapConfirmed(e); } + @Override + public boolean onDoubleTap(MotionEvent e) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) { + return super.onDoubleTap(e); + } + + if (isAccessibilityServiceEnabled(mainActivity)) { + Intent intent = new Intent(LockAccessibilityService.ACTION_LOCK, null, mainActivity, LockAccessibilityService.class); + mainActivity.startService(intent); + } else { + AlertDialog.Builder builder = new AlertDialog.Builder(mainActivity); + builder.setMessage(R.string.enable_double_tap_to_lock); + + builder.setPositiveButton(android.R.string.ok, (dialog, which) -> { + Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mainActivity.startActivity(intent); + }); + + builder.setNegativeButton(android.R.string.cancel, (dialog, which) -> { + dialog.dismiss(); + }); + + AlertDialog alert = builder.create(); + alert.show(); + } + return super.onDoubleTap(e); + } + @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { float directionY = e2.getY() - e1.getY(); @@ -95,7 +133,7 @@ private void doAction(String action) { mainActivity.showKeyboard(); break; case "display-apps": - if(mainActivity.isViewingSearchResults()) { + if (mainActivity.isViewingSearchResults()) { mainActivity.displayKissBar(true); } break; @@ -160,7 +198,7 @@ void onResume() { } } - void onTouch(View view, MotionEvent event) { + void onTouch(MotionEvent event) { // Forward touch events to the gesture detector gd.onTouchEvent(event); } @@ -225,7 +263,7 @@ private void adjustInputType() { @SuppressWarnings("CatchAndPrintStackTrace") private void displayNotificationDrawer() { @SuppressLint("WrongConstant") Object sbservice = mainActivity.getSystemService("statusbar"); - Class statusbarManager = null; + Class statusbarManager; try { statusbarManager = Class.forName("android.app.StatusBarManager"); Method showStatusBar; @@ -277,4 +315,25 @@ private boolean isKeyboardOnStartEnabled() { private boolean isSuggestionsEnabled() { return prefs.getBoolean("enable-suggestions-keyboard", false); } + + /** + * Are we allowed to run our AccessibilityService? + */ + private boolean isAccessibilityServiceEnabled(Context context) { + AccessibilityManager am = (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE); + if (am == null) { + return false; + } + + List enabledServices = am.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK); + + + for (AccessibilityServiceInfo enabledService : enabledServices) { + ServiceInfo enabledServiceInfo = enabledService.getResolveInfo().serviceInfo; + if (enabledServiceInfo.packageName.equals(context.getPackageName()) && enabledServiceInfo.name.equals(LockAccessibilityService.class.getName())) + return true; + } + + return false; + } } diff --git a/app/src/main/java/fr/neamar/kiss/forwarder/ForwarderManager.java b/app/src/main/java/fr/neamar/kiss/forwarder/ForwarderManager.java index f3d9393cd..831306155 100644 --- a/app/src/main/java/fr/neamar/kiss/forwarder/ForwarderManager.java +++ b/app/src/main/java/fr/neamar/kiss/forwarder/ForwarderManager.java @@ -82,7 +82,7 @@ public void onCreateContextMenu(ContextMenu menu) { } public boolean onTouch(View view, MotionEvent event) { - experienceTweaks.onTouch(view, event); // always return false anyway + experienceTweaks.onTouch(event); return liveWallpaperForwarder.onTouch(view, event); } diff --git a/app/src/main/java/fr/neamar/kiss/utils/LockAccessibilityService.java b/app/src/main/java/fr/neamar/kiss/utils/LockAccessibilityService.java new file mode 100644 index 000000000..e2223fb10 --- /dev/null +++ b/app/src/main/java/fr/neamar/kiss/utils/LockAccessibilityService.java @@ -0,0 +1,31 @@ +package fr.neamar.kiss.utils; + +import android.accessibilityservice.AccessibilityService; +import android.app.Service; +import android.content.Intent; +import android.os.Build; +import android.view.accessibility.AccessibilityEvent; + +public class LockAccessibilityService extends AccessibilityService { + public static String ACTION_LOCK = "fr.neamar.kiss.LOCK"; + + @Override + public void onAccessibilityEvent(AccessibilityEvent event) { + + } + + @Override + public void onInterrupt() { + + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + if (ACTION_LOCK.equals(intent.getAction())) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + performGlobalAction(AccessibilityService.GLOBAL_ACTION_LOCK_SCREEN); + } + } + return Service.START_STICKY; + } +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 64ab32f52..b875589a5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -228,6 +228,8 @@ Enlarge Move up Move down + Lock screen from KISS Launcher Action on swipe up Action on swipe down + To enable double-tap to lock, you\'ll need to grant additional permissions: enable KISS in the following screen. diff --git a/app/src/main/res/xml/lock_accessibility_service_config.xml b/app/src/main/res/xml/lock_accessibility_service_config.xml new file mode 100644 index 000000000..a787aa5fe --- /dev/null +++ b/app/src/main/res/xml/lock_accessibility_service_config.xml @@ -0,0 +1,5 @@ + + \ No newline at end of file