diff --git a/LineageActions/Android.mk b/LineageActions/Android.mk
index aabf60a..34e2458 100644
--- a/LineageActions/Android.mk
+++ b/LineageActions/Android.mk
@@ -29,10 +29,8 @@ LOCAL_RESOURCE_DIR := \
LOCAL_AAPT_FLAGS := --auto-add-overlay \
--extra-packages android.support.v14.preference:android.support.v7.appcompat:android.support.v7.preference:android.support.v7.recyclerview
-ifneq ($(INCREMENTAL_BUILDS),)
- LOCAL_PROGUARD_ENABLED := disabled
- LOCAL_JACK_ENABLED := incremental
-endif
+LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_DEX_PREOPT := false
include frameworks/base/packages/SettingsLib/common.mk
diff --git a/LineageActions/AndroidManifest.xml b/LineageActions/AndroidManifest.xml
index dc69823..37de0e0 100644
--- a/LineageActions/AndroidManifest.xml
+++ b/LineageActions/AndroidManifest.xml
@@ -10,12 +10,14 @@
+
@@ -32,7 +34,7 @@
@@ -43,7 +45,8 @@
@@ -54,6 +57,27 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/LineageActions/proguard.flags b/LineageActions/proguard.flags
deleted file mode 100644
index ab22f4b..0000000
--- a/LineageActions/proguard.flags
+++ /dev/null
@@ -1,9 +0,0 @@
--keep class org.lineageos.LineageActions.* {
- *;
-}
-
--keepclasseswithmembers class * {
- public (android.content.Context, android.util.AttributeSet);
-}
-
--keep class ** extends android.support.v14.preference.PreferenceFragment
diff --git a/LineageActions/res/drawable/ic_gesture.png b/LineageActions/res/drawable/ic_gesture.png
new file mode 100644
index 0000000..c9a3646
Binary files /dev/null and b/LineageActions/res/drawable/ic_gesture.png differ
diff --git a/LineageActions/res/drawable/ic_settings_doze.xml b/LineageActions/res/drawable/ic_settings_doze.xml
new file mode 100644
index 0000000..1cbb485
--- /dev/null
+++ b/LineageActions/res/drawable/ic_settings_doze.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
diff --git a/LineageActions/res/drawable/ic_settings_fingerprint.xml b/LineageActions/res/drawable/ic_settings_fingerprint.xml
new file mode 100644
index 0000000..a080e1c
--- /dev/null
+++ b/LineageActions/res/drawable/ic_settings_fingerprint.xml
@@ -0,0 +1,9 @@
+
+
+
+
diff --git a/LineageActions/res/drawable/ic_settings_gestures.xml b/LineageActions/res/drawable/ic_settings_gestures.xml
index 95cdede..a49a8d7 100644
--- a/LineageActions/res/drawable/ic_settings_gestures.xml
+++ b/LineageActions/res/drawable/ic_settings_gestures.xml
@@ -18,7 +18,8 @@
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
- android:viewportHeight="24">
+ android:viewportHeight="24"
+ android:tint="?android:attr/colorAccent">
+
+
+
diff --git a/LineageActions/res/values-pt-rBR/strings.xml b/LineageActions/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..8a8af86
--- /dev/null
+++ b/LineageActions/res/values-pt-rBR/strings.xml
@@ -0,0 +1,94 @@
+
+
+
+
+ Moto Ações
+
+
+ Gestos do dispositivo
+ Gerenciar os gestos do dispositivo
+
+
+ Gerenciar os gestos da tela ambiente
+
+
+ Gestos no sensor biométrico
+ Habilitar o uso de gestos no sensor biométrico
+ Gerenciar os gestos do sensor biométrico
+ Ações com a tela ligada
+ Toque único
+ Selecione a ação para toque único
+ Toque duplo
+ Selecione a ação para toque duplo
+ Toque longo
+ Selecione a ação para toque longo
+ Deslizar para a esquerda
+ Selecione a ação para deslizar para a esquerda
+ Deslizar para a direita
+ Selecione a ação para deslizar para a direita
+
+
+ Habilitar com a tela desligada
+ Habilitar os gestos no sensor biométrico quando a tela estiver desligada.\n\nO desbloqueio por impressão digital deve estar desativado para usar esse recurso.
+ Ações com a tela desligada
+
+
+ Não fazer nada
+ Início
+ Ligar/desligar tela
+ Acordar o dispositivo
+ Voltar
+ Recentes
+ Aumentar volume
+ Diminuir volume
+ Assistente de voz
+ Tocar/pausar
+ Faixa anterior
+ Próxima faixa
+ Ligar/desligar lanterna
+ Abrir câmera
+ Tirar uma captura de tela
+ Abrir navegador
+ Abrir discador
+ Abrir app de mail
+ Abrir app de mensagens
+ Modo picture-in-picture
+
+
+ Gestos com a tela desligada
+ Gerenciar os gestos com a tela desligada
+ Deslizar para a esquerda
+ Selecione a ação para deslizar para a esquerda
+ Deslizar para a direita
+ Selecione a ação para deslizar para a direita
+ Deslizar para cima
+ Selecione a ação para deslizar para cima
+ Deslizar para baixo
+ Selecione a ação para deslizar para baixo
+
+
+ Tocar para ativar
+ Toque duas vezes em qualquer parte da tela para ativar o dispositivo
+
+
+ Retorno tátil
+ Vibrar quando um gesto for detectado
+
+
+ O aplicativo não tem suporte ao modo picture-in-picture.
+
diff --git a/LineageActions/res/values/array.xml b/LineageActions/res/values/array.xml
index eb7e711..2843b4b 100644
--- a/LineageActions/res/values/array.xml
+++ b/LineageActions/res/values/array.xml
@@ -16,29 +16,87 @@
-->
- - None
- - Home
- - Power
- - Back
- - Recents
- - Volume Up
- - Volume Down
- - Voice Assistant
- - Play/Pause
- - Previous Track
- - Next Track
+ - @string/action_none
+ - @string/action_home
+ - @string/action_power
+ - @string/action_back
+ - @string/action_recents
+ - @string/action_volume_up
+ - @string/action_volume_down
+ - @string/action_voice_assistant
+ - @string/action_play_pause
+ - @string/action_previous_track
+ - @string/action_next_track
+ - @string/action_flashlight
+ - @string/action_camera
+ - @string/action_screenshot
+ - @string/action_pip
- 0
- - 102
- - 116
- - 158
- - 580
- - 115
- - 114
- - 582
- - 164
- - 165
- - 163
+ - 100
+ - 101
+ - 102
+ - 103
+ - 104
+ - 105
+ - 106
+ - 107
+ - 108
+ - 109
+ - 110
+ - 111
+ - 112
+ - 120
+
+
+
+ - @string/action_none
+ - @string/action_power
+ - @string/action_volume_up
+ - @string/action_volume_down
+ - @string/action_play_pause
+ - @string/action_previous_track
+ - @string/action_next_track
+ - @string/action_flashlight
+ - @string/action_camera
+
+
+ - 0
+ - 101
+ - 104
+ - 105
+ - 107
+ - 108
+ - 109
+ - 110
+ - 111
+
+
+
+ - @string/action_none
+ - @string/action_wake
+ - @string/action_play_pause
+ - @string/action_previous_track
+ - @string/action_next_track
+ - @string/action_flashlight
+ - @string/action_camera
+ - @string/action_browser
+ - @string/action_dialer
+ - @string/action_email
+ - @string/action_messages
+
+
+ - 0
+ - 101
+ - 107
+ - 108
+ - 109
+ - 110
+ - 111
+ - 116
+ - 117
+ - 118
+ - 119
diff --git a/LineageActions/res/values/strings.xml b/LineageActions/res/values/strings.xml
index 6e07fe2..56bd4ed 100644
--- a/LineageActions/res/values/strings.xml
+++ b/LineageActions/res/values/strings.xml
@@ -16,6 +16,79 @@
limitations under the License.
-->
+
Moto Actions
- Manage custom actions and fingerprint gestures
+
+
+ Device gestures
+ Manage device gestures
+
+
+ Manage ambient display gestures
+
+
+ Fingerprint gestures
+ Use fingerprint gestures
+ Manage fingerprint gestures
+ Actions with screen on
+ Single tap
+ Select action for single tap
+ Double tap
+ Select action for double tap
+ Long tap
+ Select action for long tap
+ Swipe left
+ Select action for swipe left
+ Swipe right
+ Select action for swipe right
+
+
+ Fingerprint gestures when screen off
+ Use fingerprint gestures when screen off.\n\nFingerprint unlocking must be disabled to use this feature.
+ Actions with screen off
+
+
+ None
+ Home
+ Screen on/off
+ Wake
+ Back
+ Recents
+ Volume up
+ Volume down
+ Voice assistant
+ Play/pause
+ Previous track
+ Next track
+ Flashlight on/off
+ Open camera
+ Take screenshot
+ Open browser
+ Open dialer
+ Open email app
+ Open messages app
+ Picture-in-Picture mode
+
+
+ Screen off gestures
+ Manage gestures when screen is off
+ Swipe left
+ Select action for swipe left
+ Swipe right
+ Select action for swipe right
+ Swipe up
+ Select action for swipe up
+ Swipe down
+ Select action for swipe down
+
+
+ Tap to wake
+ Double-tap anywhere on the screen to wake device
+
+
+ Haptic feedback
+ Vibrate when a touchscreen gesture is detected
+
+
+ App does not support picture-in-picture mode.
diff --git a/LineageActions/res/values/symbols.xml b/LineageActions/res/values/symbols.xml
new file mode 100644
index 0000000..71b806a
--- /dev/null
+++ b/LineageActions/res/values/symbols.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/LineageActions/res/xml/actions_panel.xml b/LineageActions/res/xml/actions_panel.xml
index 11f6c53..cf725f8 100644
--- a/LineageActions/res/xml/actions_panel.xml
+++ b/LineageActions/res/xml/actions_panel.xml
@@ -7,7 +7,7 @@
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
+ http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
@@ -16,157 +16,36 @@
limitations under the License.
-->
+ xmlns:settings="http://schemas.android.com/apk/res/com.android.settings">
-
+
-
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/LineageActions/res/xml/doze_panel.xml b/LineageActions/res/xml/doze_panel.xml
index bba3a9d..d50cd73 100644
--- a/LineageActions/res/xml/doze_panel.xml
+++ b/LineageActions/res/xml/doze_panel.xml
@@ -17,29 +17,24 @@
-
+
-
+
-
-
-
-
+
diff --git a/LineageActions/res/xml/fp_gesture_panel.xml b/LineageActions/res/xml/fp_gesture_panel.xml
new file mode 100644
index 0000000..63a9c84
--- /dev/null
+++ b/LineageActions/res/xml/fp_gesture_panel.xml
@@ -0,0 +1,156 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/LineageActions/res/xml/main_panel.xml b/LineageActions/res/xml/main_panel.xml
new file mode 100644
index 0000000..f368c4e
--- /dev/null
+++ b/LineageActions/res/xml/main_panel.xml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/LineageActions/res/xml/screen_off_gesture_panel.xml b/LineageActions/res/xml/screen_off_gesture_panel.xml
new file mode 100644
index 0000000..f73d272
--- /dev/null
+++ b/LineageActions/res/xml/screen_off_gesture_panel.xml
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/LineageActions/src/org/lineageos/settings/device/ActionsPreferenceActivity.java b/LineageActions/src/org/lineageos/settings/device/ActionsPreferenceActivity.java
index ceea8a6..2889b39 100644
--- a/LineageActions/src/org/lineageos/settings/device/ActionsPreferenceActivity.java
+++ b/LineageActions/src/org/lineageos/settings/device/ActionsPreferenceActivity.java
@@ -25,7 +25,9 @@ public class ActionsPreferenceActivity extends PreferenceActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- getFragmentManager().beginTransaction()
- .replace(android.R.id.content, new ActionsPreferenceFragment()).commit();
+ if (savedInstanceState == null){
+ getFragmentManager().beginTransaction()
+ .replace(android.R.id.content, new ActionsPreferenceFragment()).commit();
+ }
}
}
diff --git a/LineageActions/src/org/lineageos/settings/device/ActionsPreferenceFragment.java b/LineageActions/src/org/lineageos/settings/device/ActionsPreferenceFragment.java
index 120fce3..755c2fe 100644
--- a/LineageActions/src/org/lineageos/settings/device/ActionsPreferenceFragment.java
+++ b/LineageActions/src/org/lineageos/settings/device/ActionsPreferenceFragment.java
@@ -17,80 +17,12 @@
package org.lineageos.settings.device;
-import android.app.ActionBar;
-import android.app.AlertDialog;
-import android.app.NotificationManager;
import android.os.Bundle;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.support.v7.preference.PreferenceCategory;
import android.support.v14.preference.PreferenceFragment;
-import android.support.v7.preference.Preference;
-import android.support.v14.preference.SwitchPreference;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.text.TextUtils;
-
-import java.io.File;
-
-import org.lineageos.internal.util.FileUtils;
-import org.lineageos.settings.device.actions.Constants;
public class ActionsPreferenceFragment extends PreferenceFragment {
- private SwitchPreference mFlipPref;
- private NotificationManager mNotificationManager;
- private boolean mFlipClick = false;
-
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
- addPreferencesFromResource(R.xml.actions_panel);
- final ActionBar actionBar = getActivity().getActionBar();
- actionBar.setDisplayHomeAsUpEnabled(true);
- mNotificationManager = (NotificationManager) getActivity().getSystemService(Context.NOTIFICATION_SERVICE);
- mFlipPref = (SwitchPreference) findPreference("gesture_flip_to_mute");
- mFlipPref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
- public boolean onPreferenceClick(Preference preference) {
- if (!mNotificationManager.isNotificationPolicyAccessGranted()) {
- mFlipPref.setChecked(false);
- new AlertDialog.Builder(getContext())
- .setTitle(getString(R.string.flip_to_mute_title))
- .setMessage(getString(R.string.dnd_access))
- .setNegativeButton(android.R.string.cancel, null)
- .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- mFlipClick = true;
- startActivity(new Intent(
- android.provider.Settings.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS));
- }
- }).show();
- }
- return true;
- }
- });
-
- //Users may deny DND access after giving it
- if (!mNotificationManager.isNotificationPolicyAccessGranted()) {
- mFlipPref.setChecked(false);
- }
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- if (mNotificationManager.isNotificationPolicyAccessGranted() && mFlipClick) {
- mFlipPref.setChecked(true);
- }
- }
-
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if (item.getItemId() == android.R.id.home) {
- getActivity().onBackPressed();
- return true;
- }
- return false;
+ addPreferencesFromResource(R.xml.main_panel);
}
}
diff --git a/LineageActions/src/org/lineageos/settings/device/BootCompletedReceiver.java b/LineageActions/src/org/lineageos/settings/device/BootCompletedReceiver.java
index 01d3199..9f0492c 100644
--- a/LineageActions/src/org/lineageos/settings/device/BootCompletedReceiver.java
+++ b/LineageActions/src/org/lineageos/settings/device/BootCompletedReceiver.java
@@ -42,7 +42,7 @@ public class BootCompletedReceiver extends BroadcastReceiver {
Log.i(TAG, "Booting");
// Restore nodes to saved preference values
- for (String pref : Constants.sButtonPrefKeys) {
+ for (String pref : Constants.sPrefKeys) {
Constants.writePreference(context, pref);
}
diff --git a/LineageActions/src/org/lineageos/settings/device/DozePreferenceActivity.java b/LineageActions/src/org/lineageos/settings/device/DozePreferenceActivity.java
deleted file mode 100644
index 0047039..0000000
--- a/LineageActions/src/org/lineageos/settings/device/DozePreferenceActivity.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2017 The LineageOS Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.lineageos.settings.device;
-
-import android.os.Bundle;
-import android.preference.PreferenceActivity;
-import android.provider.Settings;
-import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceCategory;
-import android.support.v14.preference.PreferenceFragment;
-import android.support.v14.preference.SwitchPreference;
-import android.view.MenuItem;
-
-public class DozePreferenceActivity extends PreferenceActivity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- getActionBar().setDisplayHomeAsUpEnabled(true);
- getFragmentManager().beginTransaction()
- .replace(android.R.id.content, new DozePreferenceFragment()).commit();
- }
-
- public class DozePreferenceFragment extends PreferenceFragment {
- private static final String KEY_AMBIENT_DISPLAY_ENABLE = "doze_enabled";
-
- private SwitchPreference mAmbientDisplayPreference;
-
- @Override
- public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
- addPreferencesFromResource(R.xml.doze_panel);
- boolean dozeEnabled = LineageActionsSettings.isDozeEnabled(getActivity().getContentResolver());
- mAmbientDisplayPreference = (SwitchPreference) findPreference(KEY_AMBIENT_DISPLAY_ENABLE);
- // Read from DOZE_ENABLED secure setting
- mAmbientDisplayPreference.setChecked(dozeEnabled);
- mAmbientDisplayPreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
- @Override
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- boolean enable = (boolean) newValue;
- return enableDoze(enable);
- }
- });
- }
-
- private boolean enableDoze(boolean enable) {
- return Settings.Secure.putInt(getContext().getContentResolver(),
- Settings.Secure.DOZE_ENABLED, enable ? 1 : 0);
- }
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if (item.getItemId() == android.R.id.home) {
- onBackPressed();
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-}
diff --git a/LineageActions/src/org/lineageos/settings/device/DozeSettings.java b/LineageActions/src/org/lineageos/settings/device/DozeSettings.java
new file mode 100644
index 0000000..4f54250
--- /dev/null
+++ b/LineageActions/src/org/lineageos/settings/device/DozeSettings.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2017 The LineageOS Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.lineageos.settings.device;
+
+import android.os.Bundle;
+import android.preference.PreferenceActivity;
+import android.provider.Settings;
+import android.preference.Preference;
+import android.preference.PreferenceCategory;
+import android.preference.SwitchPreference;
+import android.view.MenuItem;
+
+public class DozeSettings extends PreferenceActivity {
+
+
+ private static final String KEY_AMBIENT_DISPLAY_ENABLE = "doze_enabled";
+
+ private SwitchPreference mAmbientDisplayPreference;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ addPreferencesFromResource(R.xml.doze_panel);
+ getActionBar().setDisplayHomeAsUpEnabled(true);
+ boolean dozeEnabled = LineageActionsSettings.isDozeEnabled(getContentResolver());
+ mAmbientDisplayPreference = (SwitchPreference) findPreference(KEY_AMBIENT_DISPLAY_ENABLE);
+ // Read from DOZE_ENABLED secure setting
+ mAmbientDisplayPreference.setChecked(dozeEnabled);
+ mAmbientDisplayPreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ boolean enable = (boolean) newValue;
+ return enableDoze(enable);
+ }
+ });
+ }
+
+ private boolean enableDoze(boolean enable) {
+ return Settings.Secure.putInt(getContentResolver(),
+ Settings.Secure.DOZE_ENABLED, enable ? 1 : 0);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == android.R.id.home) {
+ onBackPressed();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+}
diff --git a/LineageActions/src/org/lineageos/settings/device/FPGestureSettings.java b/LineageActions/src/org/lineageos/settings/device/FPGestureSettings.java
new file mode 100644
index 0000000..b4a64bb
--- /dev/null
+++ b/LineageActions/src/org/lineageos/settings/device/FPGestureSettings.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2016 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.lineageos.settings.device;
+
+import android.os.Bundle;
+import android.content.Context;
+import android.preference.PreferenceCategory;
+import android.preference.SwitchPreference;
+import android.hardware.fingerprint.FingerprintManager;
+import android.preference.PreferenceActivity;
+import android.view.MenuItem;
+
+public class FPGestureSettings extends PreferenceActivity {
+
+ private SwitchPreference mFPScreenOffGesture;
+ private PreferenceCategory mFPScreenOffCategory;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ addPreferencesFromResource(R.xml.fp_gesture_panel);
+ getActionBar().setDisplayHomeAsUpEnabled(true);
+ mFPScreenOffGesture = (SwitchPreference) findPreference("fp_home_scr_off");
+ mFPScreenOffCategory = (PreferenceCategory) findPreference("fp_keys_scr_off");
+ boolean hasEnrolledFingerprints = hasEnrolledFingerprints();
+ mFPScreenOffGesture.setEnabled(!hasEnrolledFingerprints);
+ mFPScreenOffCategory.setEnabled(!hasEnrolledFingerprints);
+ }
+
+ private boolean hasEnrolledFingerprints(){
+ FingerprintManager fingerprintManager = (FingerprintManager) getSystemService(Context.FINGERPRINT_SERVICE);
+ return fingerprintManager.hasEnrolledFingerprints();
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == android.R.id.home) {
+ onBackPressed();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+}
diff --git a/LineageActions/src/org/lineageos/settings/device/GestureSettings.java b/LineageActions/src/org/lineageos/settings/device/GestureSettings.java
new file mode 100644
index 0000000..f92f167
--- /dev/null
+++ b/LineageActions/src/org/lineageos/settings/device/GestureSettings.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2016 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.lineageos.settings.device;
+
+import android.app.AlertDialog;
+import android.app.NotificationManager;
+import android.os.Bundle;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceCategory;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceClickListener;
+import android.preference.SwitchPreference;
+import android.view.MenuItem;
+
+public class GestureSettings extends PreferenceActivity {
+
+ private SwitchPreference mFlipPref;
+ private NotificationManager mNotificationManager;
+ private boolean mFlipClick = false;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ addPreferencesFromResource(R.xml.actions_panel);
+ getActionBar().setDisplayHomeAsUpEnabled(true);
+ mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+ mFlipPref = (SwitchPreference) findPreference("gesture_flip_to_mute");
+
+ mFlipPref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+ public boolean onPreferenceClick(Preference preference) {
+ if (!mNotificationManager.isNotificationPolicyAccessGranted()) {
+ mFlipPref.setChecked(false);
+ new AlertDialog.Builder(GestureSettings.this)
+ .setTitle(getString(R.string.flip_to_mute_title))
+ .setMessage(getString(R.string.dnd_access))
+ .setNegativeButton(android.R.string.cancel, null)
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ mFlipClick = true;
+ startActivity(new Intent(
+ android.provider.Settings.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS));
+ }
+ }).show();
+ }
+ return true;
+ }
+ });
+
+ //Users may deny DND access after giving it
+ if (!mNotificationManager.isNotificationPolicyAccessGranted()) {
+ mFlipPref.setChecked(false);
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ if (mNotificationManager.isNotificationPolicyAccessGranted() && mFlipClick) {
+ mFlipPref.setChecked(true);
+ }
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == android.R.id.home) {
+ onBackPressed();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+}
diff --git a/LineageActions/src/org/lineageos/settings/device/KeyHandler.java b/LineageActions/src/org/lineageos/settings/device/KeyHandler.java
new file mode 100644
index 0000000..78d335c
--- /dev/null
+++ b/LineageActions/src/org/lineageos/settings/device/KeyHandler.java
@@ -0,0 +1,951 @@
+/*
+ * Copyright (C) 2016 The CyanogenMod Project
+ * Copyright (C) 2017 The LineageOS Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.lineageos.settings.device;
+
+import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
+import android.app.KeyguardManager;
+import android.app.NotificationManager;
+import android.app.ISearchManager;
+import android.widget.Toast;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.database.ContentObserver;
+import android.content.res.Resources;
+import android.content.pm.ActivityInfo;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.provider.MediaStore;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraManager;
+import android.hardware.input.InputManager;
+import android.media.AudioAttributes;
+import android.media.session.MediaSessionLegacyHelper;
+import android.os.Bundle;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.os.Vibrator;
+import android.os.VibrationEffect;
+import android.util.Log;
+import android.provider.Settings;
+import android.view.InputDevice;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.ViewConfiguration;
+import android.view.IWindowManager;
+import android.view.WindowManagerGlobal;
+import android.text.TextUtils;
+import android.Manifest;
+
+import java.util.List;
+
+import com.android.internal.os.DeviceKeyHandler;
+import com.android.internal.util.ArrayUtils;
+
+import lineageos.providers.LineageSettings;
+import org.lineageos.internal.util.FileUtils;
+
+import static org.lineageos.settings.device.actions.Constants.*;
+
+public class KeyHandler implements DeviceKeyHandler {
+
+ private static final String TAG = KeyHandler.class.getSimpleName();
+
+ private static final int GESTURE_REQUEST = 1;
+ private static final int FP_ACTION_REQUEST = 2;
+
+ private static final String ACTION_DISMISS_KEYGUARD =
+ "com.android.keyguard.action.DISMISS_KEYGUARD_SECURELY";
+
+ private static final String GESTURE_WAKEUP_REASON = "keyhandler-gesture-wakeup";
+ private static final int GESTURE_WAKELOCK_DURATION = 3000;
+
+ private final Context mContext;
+ private final PowerManager mPowerManager;
+ private final NotificationManager mNotificationManager;
+ WakeLock mProximityWakeLock;
+ WakeLock mGestureWakeLock;
+ private KeyguardManager mKeyguardManager;
+ private ScreenOffGesturesHandler mScreenOffGesturesHandler;
+ private FPScreenOffGesturesHandler mFPScreenOffGesturesHandler;
+ private SensorManager mSensorManager;
+ private CameraManager mCameraManager;
+ private String mRearCameraId;
+ private boolean mTorchEnabled;
+ private Sensor mProximitySensor;
+ private Vibrator mVibrator;
+ private int mProximityTimeOut;
+ private boolean mProximityWakeSupported;
+
+ private ISearchManager mSearchManagerService;
+
+ private Handler mHandler;
+ private int fpTapCounts = 0;
+ private boolean fpTapPending = false;
+ private boolean screenOffGesturePending = false;
+
+ public boolean mIsHapticFeedbackEnabledOnSystem;
+
+ private SettingsObserver mSettingsObserver;
+
+ private class SettingsObserver extends ContentObserver {
+ SettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ void observe() {
+ mContext.getContentResolver().registerContentObserver(Settings.System.getUriFor(
+ Settings.System.HAPTIC_FEEDBACK_ENABLED), false, this, UserHandle.USER_ALL);
+ update();
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ update();
+ }
+
+ public void update() {
+ mIsHapticFeedbackEnabledOnSystem = Settings.System.getIntForUser(mContext.getContentResolver(),
+ Settings.System.HAPTIC_FEEDBACK_ENABLED, 0, UserHandle.USER_CURRENT) == 1;
+ }
+ }
+
+ private void setHapticFeedbackEnabledOnSystem(boolean enabled){
+ Settings.System.putIntForUser(mContext.getContentResolver(),
+ Settings.System.HAPTIC_FEEDBACK_ENABLED, enabled ? 1 : 0, UserHandle.USER_CURRENT);
+ }
+
+ private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
+ .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+ .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+ .build();
+
+ public KeyHandler(Context context) {
+ mContext = context;
+
+ mSettingsObserver = new SettingsObserver(new Handler());
+ mSettingsObserver.observe();
+
+ mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ mNotificationManager
+ = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+ mScreenOffGesturesHandler = new ScreenOffGesturesHandler();
+ mFPScreenOffGesturesHandler = new FPScreenOffGesturesHandler();
+
+ mGestureWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+ "GestureWakeLock");
+
+ final Resources resources = mContext.getResources();
+ mProximityTimeOut = resources.getInteger(
+ org.lineageos.platform.internal.R.integer.config_proximityCheckTimeout);
+ mProximityWakeSupported = resources.getBoolean(
+ org.lineageos.platform.internal.R.bool.config_proximityCheckOnWake);
+
+ if (mProximityWakeSupported) {
+ mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
+ mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
+ mProximityWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+ "ProximityWakeLock");
+ }
+
+ mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
+ if (mVibrator == null || !mVibrator.hasVibrator()) {
+ mVibrator = null;
+ }
+
+ mCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
+ mCameraManager.registerTorchCallback(new MyTorchCallback(), mScreenOffGesturesHandler);
+ mCameraManager.registerTorchCallback(new MyTorchCallback(), mFPScreenOffGesturesHandler);
+
+ mHandler = new Handler(Looper.getMainLooper());
+ }
+
+ static long[] getLongIntArray(Resources r, int resid) {
+ int[] ar = r.getIntArray(resid);
+ if (ar == null) {
+ return null;
+ }
+ long[] out = new long[ar.length];
+ for (int i=0; i resInfo = pm.queryIntentActivities(intent, 0);
+ if (resInfo.isEmpty()) {
+ return null;
+ }
+ return pm.getLaunchIntentForPackage(resInfo.get(0).activityInfo.packageName);
+ }
+
+ private void triggerCameraAction(){
+ ensureKeyguardManager();
+ WakeLock wl = mPowerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "GestureWakeLock");
+ wl.acquire(500);
+ if (mKeyguardManager.inKeyguardRestrictedInputMode()) {
+ launchSecureCamera();
+ } else {
+ launchCamera();
+ }
+ }
+
+ private void launchCamera() {
+ Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.addFlags(Intent.FLAG_FROM_BACKGROUND);
+ if (getBestActivityInfo(intent) != null) {
+ // Only launch if we can succeed, but let the user pick the action
+ mContext.startActivity(intent);
+ }
+ }
+
+ private void launchSecureCamera() {
+ // Keyguard won't allow a picker, try to pick the secure intent in the package
+ // that would be the one used for a default action of launching the camera
+ Intent normalIntent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
+ normalIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ normalIntent.addFlags(Intent.FLAG_FROM_BACKGROUND);
+
+ Intent secureIntent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE);
+ secureIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ secureIntent.addFlags(Intent.FLAG_FROM_BACKGROUND);
+
+ ActivityInfo normalActivity = getBestActivityInfo(normalIntent);
+ ActivityInfo secureActivity = getBestActivityInfo(secureIntent, normalActivity);
+ if (secureActivity != null) {
+ secureIntent.setComponent(new ComponentName(secureActivity.applicationInfo.packageName, secureActivity.name));
+ mContext.startActivity(secureIntent);
+ }
+ }
+
+ private ActivityInfo getBestActivityInfo(Intent intent) {
+ PackageManager pm = mContext.getPackageManager();
+ ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
+ if (resolveInfo != null) {
+ return resolveInfo.activityInfo;
+ } else {
+ // If the resolving failed, just find our own best match
+ return getBestActivityInfo(intent, null);
+ }
+ }
+
+ private ActivityInfo getBestActivityInfo(Intent intent, ActivityInfo match) {
+ PackageManager pm = mContext.getPackageManager();
+ List activities = pm.queryIntentActivities(intent, 0);
+ ActivityInfo best = null;
+ if (activities.size() > 0) {
+ best = activities.get(0).activityInfo;
+ if (match != null) {
+ String packageName = match.applicationInfo.packageName;
+ for (int i = activities.size()-1; i >= 0; i--) {
+ ActivityInfo activityInfo = activities.get(i).activityInfo;
+ if (packageName.equals(activityInfo.applicationInfo.packageName)) {
+ best = activityInfo;
+ }
+ }
+ }
+ }
+ return best;
+ }
+
+ private void openBrowser() {
+ mGestureWakeLock.acquire(GESTURE_WAKELOCK_DURATION);
+ mPowerManager.wakeUp(SystemClock.uptimeMillis(), GESTURE_WAKEUP_REASON);
+ final Intent intent = getLaunchableIntent(
+ new Intent(Intent.ACTION_VIEW, Uri.parse("http:")));
+ startActivitySafely(intent);
+ }
+
+ private void openDialer() {
+ mGestureWakeLock.acquire(GESTURE_WAKELOCK_DURATION);
+ mPowerManager.wakeUp(SystemClock.uptimeMillis(), GESTURE_WAKEUP_REASON);
+ final Intent intent = new Intent(Intent.ACTION_DIAL, null);
+ startActivitySafely(intent);
+ }
+
+ private void openEmail() {
+ mGestureWakeLock.acquire(GESTURE_WAKELOCK_DURATION);
+ mPowerManager.wakeUp(SystemClock.uptimeMillis(), GESTURE_WAKEUP_REASON);
+ final Intent intent = getLaunchableIntent(
+ new Intent(Intent.ACTION_VIEW, Uri.parse("mailto:")));
+ startActivitySafely(intent);
+ }
+
+ private void openMessages() {
+ mGestureWakeLock.acquire(GESTURE_WAKELOCK_DURATION);
+ mPowerManager.wakeUp(SystemClock.uptimeMillis(), GESTURE_WAKEUP_REASON);
+ final String defaultApplication = Settings.Secure.getString(
+ mContext.getContentResolver(), "sms_default_application");
+ final PackageManager pm = mContext.getPackageManager();
+ final Intent intent = pm.getLaunchIntentForPackage(defaultApplication);
+ if (intent != null) {
+ startActivitySafely(intent);
+ }
+ }
+
+ private void toggleFlashlight(){
+ String rearCameraId = getRearCameraId();
+ if (rearCameraId != null) {
+ mGestureWakeLock.acquire(GESTURE_WAKELOCK_DURATION);
+ try {
+ mCameraManager.setTorchMode(rearCameraId, !mTorchEnabled);
+ mTorchEnabled = !mTorchEnabled;
+ } catch (CameraAccessException e) {
+ // Ignore
+ }
+ }
+ }
+
+ private void ensureKeyguardManager() {
+ if (mKeyguardManager == null) {
+ mKeyguardManager =
+ (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
+ }
+ }
+
+ private void resetDoubleTapOnFP() {
+ fpTapCounts = 0;
+ fpTapPending = false;
+ mHandler.removeCallbacks(doubleTapRunnable);
+ }
+
+ private Runnable doubleTapRunnable = new Runnable() {
+ public void run() {
+ int action = 0;
+ if (fpTapCounts > 1){
+ action = str2int(FileUtils.readOneLine(getFPNodeBasedOnScreenState(FP_KEY_DBLTAP_NODE)));
+ }else{
+ if (isSingleTapEnabledOnFP()){
+ action = str2int(FileUtils.readOneLine(getFPNodeBasedOnScreenState(FP_KEYS_NODE)));
+ }
+ }
+
+ if (action != 0){
+ boolean isActionSupported = ArrayUtils.contains(mPowerManager.isScreenOn() ? sFPSupportedActions : sFPSupportedActionsScreenOff, action);
+ if (isActionSupported){
+ fireFPAction(action, false);
+ }
+ }
+ resetDoubleTapOnFP();
+ }
+ };
+
+ private void detectDoubleTapOnFP() {
+ fpTapCounts++;
+ if (fpTapCounts == 1 || fpTapCounts == 2){
+ doHapticFeedbackFP(false);
+ }
+ if (!fpTapPending){
+ fpTapPending = true;
+ mHandler.postDelayed(doubleTapRunnable, ViewConfiguration.getDoubleTapTimeout());
+ }
+ }
+
+ private boolean isSingleTapEnabledOnFP() {
+ return !FileUtils.readOneLine(getFPNodeBasedOnScreenState(FP_KEYS_NODE)).equals("0");
+ }
+
+ private boolean isDoubleTapEnabledOnFP() {
+ return !FileUtils.readOneLine(getFPNodeBasedOnScreenState(FP_KEY_DBLTAP_NODE)).equals("0");
+ }
+
+ private boolean isHapticFeedbackEnabledOnFP() {
+ return !FileUtils.readOneLine(getFPNodeBasedOnScreenState(FP_HAPTIC_NODE)).equals("0");
+ }
+
+ private String getFPNodeBasedOnScreenState(String node){
+ if (mPowerManager.isScreenOn()){
+ return node;
+ }
+ switch (node) {
+ case FP_KEYS_NODE:
+ return FP_KEYS_SCREENOFF_NODE;
+ case FP_HAPTIC_NODE:
+ return FP_HAPTIC_SCREENOFF_NODE;
+ case FP_KEY_DBLTAP_NODE:
+ return FP_KEY_SCREENOFF_DBLTAP_NODE;
+ case FP_KEY_HOLD_NODE:
+ return FP_KEY_SCREENOFF_HOLD_NODE;
+ case FP_KEY_RIGHT_NODE:
+ return FP_KEY_SCREENOFF_RIGHT_NODE;
+ case FP_KEY_LEFT_NODE:
+ return FP_KEY_SCREENOFF_LEFT_NODE;
+ }
+ return node;
+ }
+
+ public boolean handleKeyEvent(KeyEvent event) {
+ int scanCode = event.getScanCode();
+
+ if (DEBUG){
+ Log.d(TAG, "DEBUG: action=" + event.getAction()
+ + ", flags=" + event.getFlags()
+ + ", keyCode=" + event.getKeyCode()
+ + ", scanCode=" + event.getScanCode()
+ + ", metaState=" + event.getMetaState()
+ + ", repeatCount=" + event.getRepeatCount());
+ }
+
+ boolean isFPScanCode = ArrayUtils.contains(sSupportedFPGestures, scanCode);
+ boolean isScreenOffGesturesScanCode = ArrayUtils.contains(sSupportedScreenOffGestures, scanCode);
+ if (!isFPScanCode && !isScreenOffGesturesScanCode) {
+ return false;
+ }
+
+ boolean isFPGestureEnabled = FileUtils.readOneLine(FP_HOME_NODE).equals("1");
+ boolean isFPGestureEnabledOnScreenOff = FileUtils.readOneLine(FP_HOME_OFF_NODE).equals("1");
+
+ boolean isScreenOn = mPowerManager.isScreenOn();
+
+ // We only want ACTION_UP event
+ if (event.getAction() != KeyEvent.ACTION_UP) {
+ return true;
+ }
+
+ if (scanCode != FP_TAP_SCANCODE){
+ resetDoubleTapOnFP();
+ }
+
+ if (isFPScanCode) {
+ if((!isFPGestureEnabled) || (!isScreenOn && !isFPGestureEnabledOnScreenOff)){
+ resetDoubleTapOnFP();
+ return false;
+ }
+ if (!isScreenOn && isFPGestureEnabledOnScreenOff){
+ processFPScreenOffScancode(scanCode);
+ }else{
+ processFPScancode(scanCode);
+ }
+ }else if (isScreenOffGesturesScanCode) {
+ processScreenOffScancode(scanCode);
+ }
+ return true;
+ }
+
+ private void processFPScancode(int scanCode){
+ int action = 0;
+ boolean isScreenOn = mPowerManager.isScreenOn();
+ switch (scanCode) {
+ case FP_TAP_SCANCODE:
+ if (isDoubleTapEnabledOnFP()) {
+ detectDoubleTapOnFP();
+ return;
+ }else{
+ resetDoubleTapOnFP();
+ action = str2int(FileUtils.readOneLine(getFPNodeBasedOnScreenState(FP_KEYS_NODE)));
+ }
+ break;
+ case FP_HOLD_SCANCODE:
+ action = str2int(FileUtils.readOneLine(getFPNodeBasedOnScreenState(FP_KEY_HOLD_NODE)));
+ break;
+ case FP_RIGHT_SCANCODE:
+ action = str2int(FileUtils.readOneLine(getFPNodeBasedOnScreenState(FP_KEY_RIGHT_NODE)));
+ break;
+ case FP_LEFT_SCANCODE:
+ action = str2int(FileUtils.readOneLine(getFPNodeBasedOnScreenState(FP_KEY_LEFT_NODE)));
+ break;
+ }
+ boolean isActionSupported = ArrayUtils.contains(isScreenOn ? sFPSupportedActions : sFPSupportedActionsScreenOff, action);
+ if (isActionSupported){
+ fireFPAction(action, true);
+ }
+ }
+
+ private void fireFPAction(int action, boolean haptic){
+ ensureKeyguardManager();
+ boolean isHapticFeedbackEnabledOnFP = isHapticFeedbackEnabledOnFP();
+ if (!haptic){
+ isHapticFeedbackEnabledOnFP = false;
+ }
+ if (isHapticFeedbackEnabledOnFP && (action == ACTION_CAMERA || action == ACTION_FLASHLIGHT)){
+ vibrate(action == ACTION_CAMERA ? 500 : 250);
+ }
+ switch (action) {
+ case ACTION_HOME:
+ if (!mKeyguardManager.inKeyguardRestrictedInputMode()){
+ triggerVirtualKeypress(mHandler, KeyEvent.KEYCODE_HOME);
+ }
+ break;
+ case ACTION_POWER:
+ toggleScreenState();
+ break;
+ case ACTION_BACK:
+ triggerVirtualKeypress(mHandler, KeyEvent.KEYCODE_BACK);
+ break;
+ case ACTION_RECENTS:
+ if (!mKeyguardManager.inKeyguardRestrictedInputMode()){
+ triggerVirtualKeypress(mHandler, KeyEvent.KEYCODE_APP_SWITCH);
+ }
+ break;
+ case ACTION_VOLUME_UP:
+ triggerVirtualKeypress(mHandler, KeyEvent.KEYCODE_VOLUME_UP);
+ break;
+ case ACTION_VOLUME_DOWN:
+ triggerVirtualKeypress(mHandler, KeyEvent.KEYCODE_VOLUME_DOWN);
+ break;
+ case ACTION_VOICE_ASSISTANT:
+ if (!mKeyguardManager.inKeyguardRestrictedInputMode()){
+ fireGoogleNowOnTap();
+ }
+ return;
+ case ACTION_PLAY_PAUSE:
+ dispatchMediaKeyWithWakeLock(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, mContext);
+ break;
+ case ACTION_PREVIOUS_TRACK:
+ dispatchMediaKeyWithWakeLock(KeyEvent.KEYCODE_MEDIA_PREVIOUS, mContext);
+ break;
+ case ACTION_NEXT_TRACK:
+ dispatchMediaKeyWithWakeLock(KeyEvent.KEYCODE_MEDIA_NEXT, mContext);
+ break;
+ case ACTION_FLASHLIGHT:
+ toggleFlashlight();
+ break;
+ case ACTION_CAMERA:
+ triggerCameraAction();
+ break;
+ case ACTION_SCREENSHOT:
+ triggerVirtualKeypress(mHandler, KeyEvent.KEYCODE_SYSRQ);
+ break;
+ case ACTION_PIP:
+ if (!mKeyguardManager.inKeyguardRestrictedInputMode()){
+ goToPipMode();
+ }
+ break;
+ }
+ if (isHapticFeedbackEnabledOnFP && action != ACTION_VOICE_ASSISTANT && action != ACTION_CAMERA && action != ACTION_FLASHLIGHT){ // prevent double vibration
+ doHapticFeedbackFP(false);
+ }
+ }
+
+ private void vibrate(int intensity){
+ if (mVibrator == null) {
+ return;
+ }
+ mVibrator.vibrate(intensity);
+ }
+
+ private void goToPipMode(){
+ ActivityInfo ai = getRunningActivityInfo(mContext);
+ if (ai != null && !ai.supportsPictureInPicture()) {
+ try {
+ PackageManager pm = mContext.getPackageManager();
+ Resources resources = pm.getResourcesForApplication("org.lineageos.settings.device");
+ int resId = resources.getIdentifier("app_does_not_support_pip", "string", "org.lineageos.settings.device");
+ final String text = resources.getString(resId);
+ mHandler.post(new Runnable() {
+ public void run() {
+ Toast.makeText(mContext, text, Toast.LENGTH_SHORT).show();
+ }
+ });
+ } catch (Exception e) {
+ }
+ return;
+ }
+ triggerVirtualKeypress(mHandler, 171);
+ }
+
+ private static ActivityInfo getRunningActivityInfo(Context context) {
+ final ActivityManager am = (ActivityManager) context
+ .getSystemService(Context.ACTIVITY_SERVICE);
+ final PackageManager pm = context.getPackageManager();
+
+ List tasks = am.getRunningTasks(1);
+ if (tasks != null && !tasks.isEmpty()) {
+ ActivityManager.RunningTaskInfo top = tasks.get(0);
+ try {
+ return pm.getActivityInfo(top.topActivity, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ }
+ }
+ return null;
+ }
+
+ private void toggleScreenState(){
+ if(mPowerManager.isScreenOn()){
+ mPowerManager.goToSleep(SystemClock.uptimeMillis());
+ }else{
+ mPowerManager.wakeUp(SystemClock.uptimeMillis());
+ }
+ }
+
+ private static void dispatchMediaKeyWithWakeLock(int keycode, Context context) {
+ if (ActivityManagerNative.isSystemReady()) {
+ KeyEvent event = new KeyEvent(SystemClock.uptimeMillis(),
+ SystemClock.uptimeMillis(), KeyEvent.ACTION_DOWN, keycode, 0);
+ MediaSessionLegacyHelper.getHelper(context).sendMediaButtonEvent(event, true);
+ event = KeyEvent.changeAction(event, KeyEvent.ACTION_UP);
+ MediaSessionLegacyHelper.getHelper(context).sendMediaButtonEvent(event, true);
+ }
+ }
+
+ private void triggerVirtualKeypress(final Handler handler, final int keyCode) {
+ final boolean mIsHapticFeedbackEnabledOnSystem_ = mIsHapticFeedbackEnabledOnSystem;
+ if (mIsHapticFeedbackEnabledOnSystem_){
+ setHapticFeedbackEnabledOnSystem(false);
+ }
+ final InputManager im = InputManager.getInstance();
+ long now = SystemClock.uptimeMillis();
+
+ final KeyEvent downEvent = new KeyEvent(now, now, KeyEvent.ACTION_DOWN,
+ keyCode, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
+ KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY, InputDevice.SOURCE_CLASS_BUTTON);
+ final KeyEvent upEvent = KeyEvent.changeAction(downEvent,
+ KeyEvent.ACTION_UP);
+
+ // add a small delay to make sure everything behind got focus
+ handler.post(new Runnable(){
+ @Override
+ public void run() {
+ im.injectInputEvent(downEvent,InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+ }});
+
+ handler.postDelayed(new Runnable(){
+ @Override
+ public void run() {
+ im.injectInputEvent(upEvent, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+ if (mIsHapticFeedbackEnabledOnSystem_){
+ setHapticFeedbackEnabledOnSystem(true);
+ }
+ }}, 10);
+ }
+
+ private static void sendCloseSystemWindows(String reason) {
+ if (ActivityManagerNative.isSystemReady()) {
+ try {
+ ActivityManagerNative.getDefault().closeSystemDialogs(reason);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ private void fireGoogleNowOnTap() {
+ doHapticFeedbackFP(false);
+ mSearchManagerService = ISearchManager.Stub.asInterface(ServiceManager.getService(Context.SEARCH_SERVICE));
+ if (mSearchManagerService != null) {
+ try {
+ mSearchManagerService.launchAssist(new Bundle());
+ } catch (RemoteException e) {
+ }
+ }
+ doHapticFeedbackFP(true);
+ }
+
+ private int str2int(String str){
+ if (str == null || str.isEmpty()){
+ return 0;
+ }
+ try {
+ return Integer.valueOf(str);
+ } catch (Exception e) {
+ return 0;
+ }
+ }
+
+ private void processFPScreenOffScancode(int scanCode){
+ if (!mFPScreenOffGesturesHandler.hasMessages(FP_ACTION_REQUEST)) {
+ Message msg = mFPScreenOffGesturesHandler.obtainMessage(FP_ACTION_REQUEST);
+ msg.arg1 = scanCode;
+ boolean defaultProximity = mContext.getResources().getBoolean(
+ org.lineageos.platform.internal.R.bool.config_proximityCheckOnWakeEnabledByDefault);
+ boolean proximityWakeCheckEnabled = LineageSettings.System.getInt(mContext.getContentResolver(),
+ LineageSettings.System.PROXIMITY_ON_WAKE, defaultProximity ? 1 : 0) == 1;
+ if (mProximityWakeSupported && proximityWakeCheckEnabled && mProximitySensor != null) {
+ mFPScreenOffGesturesHandler.sendMessageDelayed(msg, mProximityTimeOut);
+ registerFPScreenOffListener(scanCode);
+ }else{
+ mFPScreenOffGesturesHandler.sendMessage(msg);
+ }
+ }
+ }
+
+ private void registerFPScreenOffListener(final int scanCode) {
+ mProximityWakeLock.acquire();
+ mSensorManager.registerListener(new SensorEventListener() {
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ mProximityWakeLock.release();
+ mSensorManager.unregisterListener(this);
+ if (!mFPScreenOffGesturesHandler.hasMessages(FP_ACTION_REQUEST)) {
+ // The sensor took to long, ignoring.
+ return;
+ }
+ mFPScreenOffGesturesHandler.removeMessages(FP_ACTION_REQUEST);
+ if (event.values[0] == mProximitySensor.getMaximumRange()) {
+ Message msg = mFPScreenOffGesturesHandler.obtainMessage(FP_ACTION_REQUEST);
+ msg.arg1 = scanCode;
+ mFPScreenOffGesturesHandler.sendMessage(msg);
+ }
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ }
+
+ }, mProximitySensor, SensorManager.SENSOR_DELAY_FASTEST);
+ }
+
+
+ private void resetScreenOffGestureDelay() {
+ screenOffGesturePending = false;
+ mHandler.removeCallbacks(screenOffGestureRunnable);
+ }
+
+ private Runnable screenOffGestureRunnable = new Runnable() {
+ public void run() {
+ resetScreenOffGestureDelay();
+ }
+ };
+
+ private void processScreenOffScancode(int scanCode){
+ if (screenOffGesturePending){
+ return;
+ }else{
+ resetScreenOffGestureDelay();
+ screenOffGesturePending = true;
+ mHandler.postDelayed(screenOffGestureRunnable, 500);
+ }
+ if (!mScreenOffGesturesHandler.hasMessages(GESTURE_REQUEST)) {
+ Message msg = mScreenOffGesturesHandler.obtainMessage(GESTURE_REQUEST);
+ msg.arg1 = scanCode;
+ boolean defaultProximity = mContext.getResources().getBoolean(
+ org.lineageos.platform.internal.R.bool.config_proximityCheckOnWakeEnabledByDefault);
+ boolean proximityWakeCheckEnabled = LineageSettings.System.getInt(mContext.getContentResolver(),
+ LineageSettings.System.PROXIMITY_ON_WAKE, defaultProximity ? 1 : 0) == 1;
+ if (mProximityWakeSupported && proximityWakeCheckEnabled && mProximitySensor != null) {
+ mScreenOffGesturesHandler.sendMessageDelayed(msg, mProximityTimeOut);
+ registerScreenOffGesturesListener(scanCode);
+ } else {
+ mScreenOffGesturesHandler.sendMessage(msg);
+ }
+ }
+ }
+
+ private void registerScreenOffGesturesListener(final int scanCode) {
+ mProximityWakeLock.acquire();
+ mSensorManager.registerListener(new SensorEventListener() {
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ mProximityWakeLock.release();
+ mSensorManager.unregisterListener(this);
+ if (!mScreenOffGesturesHandler.hasMessages(GESTURE_REQUEST)) {
+ // The sensor took to long, ignoring.
+ return;
+ }
+ mScreenOffGesturesHandler.removeMessages(GESTURE_REQUEST);
+ if (event.values[0] == mProximitySensor.getMaximumRange()) {
+ Message msg = mScreenOffGesturesHandler.obtainMessage(GESTURE_REQUEST);
+ msg.arg1 = scanCode;
+ mScreenOffGesturesHandler.sendMessage(msg);
+ }
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ }
+
+ }, mProximitySensor, SensorManager.SENSOR_DELAY_FASTEST);
+ }
+
+ private class ScreenOffGesturesHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ int scanCode = msg.arg1;
+ int action = 0;
+ switch (scanCode) {
+ case GESTURE_SWIPE_RIGHT_SCANCODE:
+ action = str2int(FileUtils.readOneLine(GESTURE_SWIPE_RIGHT_NODE));
+ break;
+ case GESTURE_SWIPE_LEFT_SCANCODE:
+ action = str2int(FileUtils.readOneLine(GESTURE_SWIPE_LEFT_NODE));
+ break;
+ case GESTURE_SWIPE_DOWN_SCANCODE:
+ action = str2int(FileUtils.readOneLine(GESTURE_SWIPE_DOWN_NODE));
+ break;
+ case GESTURE_SWIPE_UP_SCANCODE:
+ action = str2int(FileUtils.readOneLine(GESTURE_SWIPE_UP_NODE));
+ break;
+ case GESTURE_DOUBLE_TAP_SCANCODE:
+ action = str2int(FileUtils.readOneLine(GESTURE_DOUBLE_TAP_NODE));
+ if (action != 0){
+ action = ACTION_POWER;
+ }
+ break;
+ }
+ boolean isActionSupported = ArrayUtils.contains(sScreenOffSupportedActions, action);
+ if(isActionSupported){
+ fireScreenOffAction(action);
+ }
+ }
+ }
+
+ private void fireScreenOffAction(int action){
+ boolean haptic = Settings.System.getInt(mContext.getContentResolver(), KEY_GESTURE_ENABLE_HAPTIC_FEEDBACK, 1) != 0;
+ if (haptic && (action == ACTION_CAMERA || action == ACTION_FLASHLIGHT)){
+ vibrate(action == ACTION_CAMERA ? 500 : 250);
+ }
+ switch (action) {
+ case ACTION_POWER:
+ toggleScreenState();
+ break;
+ case ACTION_PLAY_PAUSE:
+ dispatchMediaKeyWithWakeLock(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, mContext);
+ break;
+ case ACTION_PREVIOUS_TRACK:
+ dispatchMediaKeyWithWakeLock(KeyEvent.KEYCODE_MEDIA_PREVIOUS, mContext);
+ break;
+ case ACTION_NEXT_TRACK:
+ dispatchMediaKeyWithWakeLock(KeyEvent.KEYCODE_MEDIA_NEXT, mContext);
+ break;
+ case ACTION_FLASHLIGHT:
+ toggleFlashlight();
+ break;
+ case ACTION_CAMERA:
+ triggerCameraAction();
+ break;
+ case ACTION_BROWSER:
+ openBrowser();
+ break;
+ case ACTION_DIALER:
+ openDialer();
+ break;
+ case ACTION_EMAIL:
+ openEmail();
+ break;
+ case ACTION_MESSAGES:
+ openMessages();
+ break;
+ }
+ if (action != ACTION_FLASHLIGHT && action != ACTION_CAMERA){
+ doHapticFeedbackScreenOff();
+ }
+ }
+
+ private class FPScreenOffGesturesHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ processFPScancode(msg.arg1);
+ }
+ }
+
+ private void startActivitySafely(Intent intent) {
+ intent.addFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_SINGLE_TOP
+ | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ try {
+ UserHandle user = new UserHandle(UserHandle.USER_CURRENT);
+ mContext.startActivityAsUser(intent, null, user);
+ } catch (ActivityNotFoundException e) {
+ // Ignore
+ }
+ }
+
+ private void doHapticFeedbackScreenOff() {
+ if (mVibrator == null) {
+ return;
+ }
+ boolean enabled = Settings.System.getInt(mContext.getContentResolver(), KEY_GESTURE_ENABLE_HAPTIC_FEEDBACK, 1) != 0;
+ if (enabled) {
+ mVibrator.vibrate(50);
+ }
+ }
+
+ private void doHapticFeedbackFP(boolean longpress) {
+ if (mVibrator == null) {
+ return;
+ }
+
+ if (isHapticFeedbackEnabledOnFP()) {
+ long[] pattern = null;
+ int owningUid;
+ String owningPackage;
+ owningUid = android.os.Process.myUid();
+ owningPackage = mContext.getOpPackageName();
+ VibrationEffect effect;
+ if (longpress){
+ pattern = getLongIntArray(mContext.getResources(),com.android.internal.R.array.config_longPressVibePattern);
+ }else{
+ pattern = getLongIntArray(mContext.getResources(),com.android.internal.R.array.config_virtualKeyVibePattern);
+ }
+ if (pattern.length == 0) {
+ // No vibration
+ return;
+ } else if (pattern.length == 1) {
+ // One-shot vibration
+ effect = VibrationEffect.createOneShot(pattern[0], VibrationEffect.DEFAULT_AMPLITUDE);
+ } else {
+ // Pattern vibration
+ effect = VibrationEffect.createWaveform(pattern, -1);
+ }
+ mVibrator.vibrate(owningUid, owningPackage, effect, VIBRATION_ATTRIBUTES);
+ }
+ }
+
+ private class MyTorchCallback extends CameraManager.TorchCallback {
+ @Override
+ public void onTorchModeChanged(String cameraId, boolean enabled) {
+ if (!cameraId.equals(mRearCameraId))
+ return;
+ mTorchEnabled = enabled;
+ }
+
+ @Override
+ public void onTorchModeUnavailable(String cameraId) {
+ if (!cameraId.equals(mRearCameraId))
+ return;
+ mTorchEnabled = false;
+ }
+ }
+}
diff --git a/LineageActions/src/org/lineageos/settings/device/LineageActionsSettings.java b/LineageActions/src/org/lineageos/settings/device/LineageActionsSettings.java
index 8cb1804..c552d10 100644
--- a/LineageActions/src/org/lineageos/settings/device/LineageActionsSettings.java
+++ b/LineageActions/src/org/lineageos/settings/device/LineageActionsSettings.java
@@ -134,7 +134,9 @@ public class LineageActionsSettings {
mFlipToMuteEnabled = sharedPreferences.getBoolean(GESTURE_FLIP_TO_MUTE_KEY, false);
} else if (GESTURE_LIFT_TO_SILENCE_KEY.equals(key)) {
mLiftToSilenceEnabled = sharedPreferences.getBoolean(GESTURE_LIFT_TO_SILENCE_KEY, false);
- } else if (Constants.FP_HOME_KEY.equals(key) || Constants.FP_HAPTIC_KEY.equals(key) || Constants.FP_KEYS.equals(key) || Constants.FP_KEY_HOLD.equals(key) || Constants.FP_KEY_LEFT.equals(key) || Constants.FP_KEY_RIGHT.equals(key)) {
+ } else if (Constants.FP_HOME_KEY.equals(key) || Constants.FP_HAPTIC_KEY.equals(key) || Constants.FP_HOME_KEY_OFF.equals(key) || Constants.FP_HAPTIC_SCREENOFF_KEY.equals(key) || Constants.FP_KEYS.equals(key) || Constants.FP_KEY_DBLTAP.equals(key) || Constants.FP_KEY_HOLD.equals(key) || Constants.FP_KEY_LEFT.equals(key) || Constants.FP_KEY_RIGHT.equals(key)
+ || Constants.FP_KEYS_OFF.equals(key) || Constants.FP_KEY_DBLTAP_OFF.equals(key) || Constants.FP_KEY_HOLD_OFF.equals(key) || Constants.FP_KEY_LEFT_OFF.equals(key) || Constants.FP_KEY_RIGHT_OFF.equals(key)
+ || Constants.GESTURE_SWIPE_RIGHT.equals(key) || Constants.GESTURE_SWIPE_LEFT.equals(key) || Constants.GESTURE_SWIPE_DOWN.equals(key) || Constants.GESTURE_SWIPE_UP.equals(key)) {
Constants.writePreference(mContext, key);
updated = false;
} else {
diff --git a/LineageActions/src/org/lineageos/settings/device/ScreenOffGestureSettings.java b/LineageActions/src/org/lineageos/settings/device/ScreenOffGestureSettings.java
new file mode 100644
index 0000000..107c914
--- /dev/null
+++ b/LineageActions/src/org/lineageos/settings/device/ScreenOffGestureSettings.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2016 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.lineageos.settings.device;
+
+import android.os.Bundle;
+import android.provider.Settings;
+import android.preference.Preference;
+import android.preference.SwitchPreference;
+import android.preference.PreferenceActivity;
+import android.view.MenuItem;
+
+import static android.provider.Settings.Secure.DOUBLE_TAP_TO_WAKE;
+import static org.lineageos.settings.device.actions.Constants.KEY_GESTURE_ENABLE_HAPTIC_FEEDBACK;
+
+public class ScreenOffGestureSettings extends PreferenceActivity {
+
+ private SwitchPreference mTapToWake;
+ private SwitchPreference mHapticFeedback;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ addPreferencesFromResource(R.xml.screen_off_gesture_panel);
+ getActionBar().setDisplayHomeAsUpEnabled(true);
+ mTapToWake = (SwitchPreference) findPreference("tap_to_wake");
+ mTapToWake.setChecked(Settings.Secure.getInt(getContentResolver(), DOUBLE_TAP_TO_WAKE, 0) == 1);
+ mTapToWake.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object objValue) {
+ boolean value = (Boolean) objValue;
+ Settings.Secure.putInt(getContentResolver(), DOUBLE_TAP_TO_WAKE, value ? 1 : 0);
+ return true;
+ }
+ });
+
+ mHapticFeedback = (SwitchPreference) findPreference("haptic_feedback");
+ mHapticFeedback.setChecked(Settings.System.getInt(getContentResolver(), KEY_GESTURE_ENABLE_HAPTIC_FEEDBACK, 1) == 1);
+ mHapticFeedback.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object objValue) {
+ boolean value = (Boolean) objValue;
+ Settings.System.putInt(getContentResolver(), KEY_GESTURE_ENABLE_HAPTIC_FEEDBACK, value ? 1 : 0);
+ return true;
+ }
+ });
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == android.R.id.home) {
+ onBackPressed();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+}
diff --git a/LineageActions/src/org/lineageos/settings/device/actions/Constants.java b/LineageActions/src/org/lineageos/settings/device/actions/Constants.java
index 9f7d287..d94fca9 100644
--- a/LineageActions/src/org/lineageos/settings/device/actions/Constants.java
+++ b/LineageActions/src/org/lineageos/settings/device/actions/Constants.java
@@ -29,8 +29,68 @@ import org.lineageos.internal.util.FileUtils;
public class Constants {
+ public static final boolean DEBUG = false;
+
private static final String TAG = "LineageActions";
+ // FP gestures
+ public static final int FP_TAP_SCANCODE = 616;
+ public static final int FP_HOLD_SCANCODE = 617;
+ public static final int FP_RIGHT_SCANCODE = 620;
+ public static final int FP_LEFT_SCANCODE = 621;
+ public static final int[] sSupportedFPGestures = new int[]{
+ FP_TAP_SCANCODE,
+ FP_HOLD_SCANCODE,
+ FP_RIGHT_SCANCODE,
+ FP_LEFT_SCANCODE
+ };
+
+ // FP actions
+ public static final int ACTION_HOME = 100;
+ public static final int ACTION_POWER = 101;
+ public static final int ACTION_BACK = 102;
+ public static final int ACTION_RECENTS = 103;
+ public static final int ACTION_VOLUME_UP = 104;
+ public static final int ACTION_VOLUME_DOWN = 105;
+ public static final int ACTION_VOICE_ASSISTANT = 106;
+ public static final int ACTION_PLAY_PAUSE = 107;
+ public static final int ACTION_PREVIOUS_TRACK = 108;
+ public static final int ACTION_NEXT_TRACK = 109;
+ public static final int ACTION_FLASHLIGHT = 110;
+ public static final int ACTION_CAMERA = 111;
+ public static final int ACTION_SCREENSHOT = 112;
+ public static final int ACTION_BROWSER = 116;
+ public static final int ACTION_DIALER = 117;
+ public static final int ACTION_EMAIL = 118;
+ public static final int ACTION_MESSAGES = 119;
+ public static final int ACTION_PIP = 120;
+ public static final int[] sFPSupportedActions = new int[]{
+ ACTION_HOME,
+ ACTION_POWER,
+ ACTION_BACK,
+ ACTION_RECENTS,
+ ACTION_VOLUME_UP,
+ ACTION_VOLUME_DOWN,
+ ACTION_VOICE_ASSISTANT,
+ ACTION_PLAY_PAUSE,
+ ACTION_PREVIOUS_TRACK,
+ ACTION_NEXT_TRACK,
+ ACTION_FLASHLIGHT,
+ ACTION_CAMERA,
+ ACTION_SCREENSHOT,
+ ACTION_PIP
+ };
+ public static final int[] sFPSupportedActionsScreenOff = new int[]{
+ ACTION_POWER,
+ ACTION_VOLUME_UP,
+ ACTION_VOLUME_DOWN,
+ ACTION_PLAY_PAUSE,
+ ACTION_PREVIOUS_TRACK,
+ ACTION_NEXT_TRACK,
+ ACTION_FLASHLIGHT,
+ ACTION_CAMERA
+ };
+
// Swap keys
public static final String FP_HOME_KEY = "fp_home";
public static final String FP_HOME_KEY_OFF = "fp_home_scr_off";
@@ -42,71 +102,142 @@ public class Constants {
// Haptic node
public static final String FP_HAPTIC_NODE = "/sys/homebutton/haptic";
public static final String FP_HAPTIC_KEY = "fp_haptic";
+ public static final String FP_HAPTIC_SCREENOFF_NODE = "/sys/homebutton/haptic_off";
+ public static final String FP_HAPTIC_SCREENOFF_KEY = "fp_haptic_scr_off";
// List of keys
public static final String FP_KEYS = "fp_keys";
+ public static final String FP_KEY_DBLTAP = "fp_key_dbltap";
public static final String FP_KEY_HOLD = "fp_key_hold";
public static final String FP_KEY_LEFT = "fp_key_left";
public static final String FP_KEY_RIGHT = "fp_key_right";
public static final String FP_KEYS_OFF = "fp_keys_off";
+ public static final String FP_KEY_DBLTAP_OFF = "fp_key_dbltap_off";
public static final String FP_KEY_HOLD_OFF = "fp_key_hold_off";
public static final String FP_KEY_LEFT_OFF = "fp_key_left_off";
public static final String FP_KEY_RIGHT_OFF = "fp_key_right_off";
// Keys nodes
public static final String FP_KEYS_NODE = "/sys/homebutton/key";
+ public static final String FP_KEY_DBLTAP_NODE = "/sys/homebutton/key_dbltap";
public static final String FP_KEY_HOLD_NODE = "/sys/homebutton/key_hold";
public static final String FP_KEY_LEFT_NODE = "/sys/homebutton/key_left";
public static final String FP_KEY_RIGHT_NODE = "/sys/homebutton/key_right";
+ public static final String FP_KEYS_SCREENOFF_NODE = "/sys/homebutton/key_screenoff";
+ public static final String FP_KEY_SCREENOFF_DBLTAP_NODE = "/sys/homebutton/key_screenoff_dbltap";
+ public static final String FP_KEY_SCREENOFF_HOLD_NODE = "/sys/homebutton/key_screenoff_hold";
+ public static final String FP_KEY_SCREENOFF_LEFT_NODE = "/sys/homebutton/key_screenoff_left";
+ public static final String FP_KEY_SCREENOFF_RIGHT_NODE = "/sys/homebutton/key_screenoff_right";
+
+ // Screen off gestures
+ public static final int GESTURE_SWIPE_RIGHT_SCANCODE = 622;
+ public static final int GESTURE_SWIPE_LEFT_SCANCODE = 623;
+ public static final int GESTURE_SWIPE_DOWN_SCANCODE = 624;
+ public static final int GESTURE_SWIPE_UP_SCANCODE = 625;
+ public static final int GESTURE_DOUBLE_TAP_SCANCODE = 626;
+ public static final int[] sSupportedScreenOffGestures = new int[]{
+ GESTURE_SWIPE_RIGHT_SCANCODE,
+ GESTURE_SWIPE_LEFT_SCANCODE,
+ GESTURE_SWIPE_DOWN_SCANCODE,
+ GESTURE_SWIPE_UP_SCANCODE,
+ GESTURE_DOUBLE_TAP_SCANCODE
+ };
+ public static final int[] sScreenOffSupportedActions = new int[]{
+ ACTION_POWER,
+ ACTION_PLAY_PAUSE,
+ ACTION_PREVIOUS_TRACK,
+ ACTION_NEXT_TRACK,
+ ACTION_FLASHLIGHT,
+ ACTION_CAMERA,
+ ACTION_BROWSER,
+ ACTION_DIALER,
+ ACTION_EMAIL,
+ ACTION_MESSAGES
+ };
+
+ // List of screen off gestures keys
+ public static final String GESTURE_SWIPE_RIGHT = "screen_off_gestures_swipe_right";
+ public static final String GESTURE_SWIPE_LEFT = "screen_off_gestures_swipe_left";
+ public static final String GESTURE_SWIPE_DOWN = "screen_off_gestures_swipe_down";
+ public static final String GESTURE_SWIPE_UP = "screen_off_gestures_swipe_up";
+
+ // Screen off gestures nodes
+ public static final String GESTURE_SWIPE_RIGHT_NODE = "/sys/android_touch/gesture_swipe_right";
+ public static final String GESTURE_SWIPE_LEFT_NODE = "/sys/android_touch/gesture_swipe_left";
+ public static final String GESTURE_SWIPE_DOWN_NODE = "/sys/android_touch/gesture_swipe_down";
+ public static final String GESTURE_SWIPE_UP_NODE = "/sys/android_touch/gesture_swipe_up";
+ public static final String GESTURE_DOUBLE_TAP_NODE = "/sys/android_touch/doubletap2wake";
+
+ // Screen off gestures haptic
+ public static final String KEY_GESTURE_ENABLE_HAPTIC_FEEDBACK = "screen_off_gesture_haptic_feedback";
+
// Holds -> mapping
public static final Map sBooleanNodePreferenceMap = new HashMap<>();
// Holds -> mapping
public static final Map sNodeDefaultMap = new HashMap<>();
- public static final String[] sButtonPrefKeys = {
+ public static final String[] sPrefKeys = {
FP_HOME_KEY,
FP_HOME_KEY_OFF,
+ FP_HAPTIC_KEY,
+ FP_HAPTIC_SCREENOFF_KEY,
FP_KEYS,
+ FP_KEY_DBLTAP,
FP_KEY_HOLD,
FP_KEY_RIGHT,
FP_KEY_LEFT,
- FP_HAPTIC_KEY,
- };
-
- public static final String[] sButtonScreenOffPrefKeys = {
FP_KEYS_OFF,
+ FP_KEY_DBLTAP_OFF,
FP_KEY_HOLD_OFF,
FP_KEY_RIGHT_OFF,
FP_KEY_LEFT_OFF,
FP_HOME_KEY_OFF,
+ GESTURE_SWIPE_RIGHT,
+ GESTURE_SWIPE_LEFT,
+ GESTURE_SWIPE_DOWN,
+ GESTURE_SWIPE_UP
};
static {
sBooleanNodePreferenceMap.put(FP_HOME_KEY, FP_HOME_NODE);
sBooleanNodePreferenceMap.put(FP_HOME_KEY_OFF, FP_HOME_OFF_NODE);
+ sBooleanNodePreferenceMap.put(FP_HAPTIC_KEY, FP_HAPTIC_NODE);
+ sBooleanNodePreferenceMap.put(FP_HAPTIC_SCREENOFF_KEY, FP_HAPTIC_SCREENOFF_NODE);
sBooleanNodePreferenceMap.put(FP_KEYS, FP_KEYS_NODE);
+ sBooleanNodePreferenceMap.put(FP_KEY_DBLTAP, FP_KEY_DBLTAP_NODE);
sBooleanNodePreferenceMap.put(FP_KEY_HOLD, FP_KEY_HOLD_NODE);
sBooleanNodePreferenceMap.put(FP_KEY_LEFT, FP_KEY_LEFT_NODE);
sBooleanNodePreferenceMap.put(FP_KEY_RIGHT, FP_KEY_RIGHT_NODE);
- sBooleanNodePreferenceMap.put(FP_HAPTIC_KEY, FP_HAPTIC_NODE);
- sBooleanNodePreferenceMap.put(FP_KEYS_OFF, FP_KEYS_NODE);
- sBooleanNodePreferenceMap.put(FP_KEY_HOLD_OFF, FP_KEY_HOLD_NODE);
- sBooleanNodePreferenceMap.put(FP_KEY_LEFT_OFF, FP_KEY_LEFT_NODE);
- sBooleanNodePreferenceMap.put(FP_KEY_RIGHT_OFF, FP_KEY_RIGHT_NODE);
+ sBooleanNodePreferenceMap.put(FP_KEYS_OFF, FP_KEYS_SCREENOFF_NODE);
+ sBooleanNodePreferenceMap.put(FP_KEY_DBLTAP_OFF, FP_KEY_SCREENOFF_DBLTAP_NODE);
+ sBooleanNodePreferenceMap.put(FP_KEY_HOLD_OFF, FP_KEY_SCREENOFF_HOLD_NODE);
+ sBooleanNodePreferenceMap.put(FP_KEY_LEFT_OFF, FP_KEY_SCREENOFF_LEFT_NODE);
+ sBooleanNodePreferenceMap.put(FP_KEY_RIGHT_OFF, FP_KEY_SCREENOFF_RIGHT_NODE);
+ sBooleanNodePreferenceMap.put(GESTURE_SWIPE_RIGHT, GESTURE_SWIPE_RIGHT_NODE);
+ sBooleanNodePreferenceMap.put(GESTURE_SWIPE_LEFT, GESTURE_SWIPE_LEFT_NODE);
+ sBooleanNodePreferenceMap.put(GESTURE_SWIPE_DOWN, GESTURE_SWIPE_DOWN_NODE);
+ sBooleanNodePreferenceMap.put(GESTURE_SWIPE_UP, GESTURE_SWIPE_UP_NODE);
sNodeDefaultMap.put(FP_HOME_KEY, false);
sNodeDefaultMap.put(FP_HOME_KEY_OFF, false);
+ sNodeDefaultMap.put(FP_HAPTIC_KEY, false);
+ sNodeDefaultMap.put(FP_HAPTIC_SCREENOFF_KEY, false);
sNodeDefaultMap.put(FP_KEYS, "0");
+ sNodeDefaultMap.put(FP_KEY_DBLTAP, "0");
sNodeDefaultMap.put(FP_KEY_HOLD, "0");
sNodeDefaultMap.put(FP_KEY_LEFT, "0");
sNodeDefaultMap.put(FP_KEY_RIGHT, "0");
sNodeDefaultMap.put(FP_KEYS_OFF, "0");
+ sNodeDefaultMap.put(FP_KEY_DBLTAP_OFF, "0");
sNodeDefaultMap.put(FP_KEY_HOLD_OFF, "0");
sNodeDefaultMap.put(FP_KEY_LEFT_OFF, "0");
sNodeDefaultMap.put(FP_KEY_RIGHT_OFF, "0");
- sNodeDefaultMap.put(FP_HAPTIC_KEY, false);
+ sNodeDefaultMap.put(GESTURE_SWIPE_RIGHT, "0");
+ sNodeDefaultMap.put(GESTURE_SWIPE_LEFT, "0");
+ sNodeDefaultMap.put(GESTURE_SWIPE_DOWN, "0");
+ sNodeDefaultMap.put(GESTURE_SWIPE_UP, "0");
}
public static boolean isPreferenceEnabled(Context context, String key) {
@@ -123,8 +254,8 @@ public class Constants {
String value = "1";
Log.e(TAG, "Write Pref: " + pref);
- if (!pref.equals(FP_KEYS) && !pref.equals(FP_KEY_HOLD) && !pref.equals(FP_KEY_LEFT) && !pref.equals(FP_KEY_RIGHT) &&
- !pref.equals(FP_KEYS_OFF) && !pref.equals(FP_KEY_HOLD_OFF) && !pref.equals(FP_KEY_LEFT_OFF) && !pref.equals(FP_KEY_RIGHT_OFF))
+ if (!pref.equals(FP_KEYS) && !pref.equals(FP_KEY_DBLTAP) && !pref.equals(FP_KEY_HOLD) && !pref.equals(FP_KEY_LEFT) && !pref.equals(FP_KEY_RIGHT) &&
+ !pref.equals(FP_KEYS_OFF) && !pref.equals(FP_KEY_DBLTAP_OFF) && !pref.equals(FP_KEY_HOLD_OFF) && !pref.equals(FP_KEY_LEFT_OFF) && !pref.equals(FP_KEY_RIGHT_OFF) && !pref.equals(GESTURE_SWIPE_RIGHT) && !pref.equals(GESTURE_SWIPE_LEFT) && !pref.equals(GESTURE_SWIPE_DOWN) && !pref.equals(GESTURE_SWIPE_UP))
value = isPreferenceEnabled(context, pref) ? "1" : "0";
else
value = GetPreference(context, pref);
diff --git a/LineageActions/src/org/lineageos/settings/device/doze/ScreenReceiver.java b/LineageActions/src/org/lineageos/settings/device/doze/ScreenReceiver.java
index 924c2b1..cec01d0 100644
--- a/LineageActions/src/org/lineageos/settings/device/doze/ScreenReceiver.java
+++ b/LineageActions/src/org/lineageos/settings/device/doze/ScreenReceiver.java
@@ -41,16 +41,8 @@ public class ScreenReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
mNotifier.screenTurnedOff();
-
- for (String pref : Constants.sButtonScreenOffPrefKeys) {
- Constants.writePreference(context, pref);
- }
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
mNotifier.screenTurnedOn();
-
- for (String pref : Constants.sButtonPrefKeys) {
- Constants.writePreference(context, pref);
- }
}
}
}
diff --git a/overlay-lineage/lineage-sdk/lineage/res/res/values/config.xml b/overlay-lineage/lineage-sdk/lineage/res/res/values/config.xml
index bb1ca9f..7e966fb 100644
--- a/overlay-lineage/lineage-sdk/lineage/res/res/values/config.xml
+++ b/overlay-lineage/lineage-sdk/lineage/res/res/values/config.xml
@@ -56,4 +56,14 @@
false
+
+
+ - /system/priv-app/LineageActions/LineageActions.apk
+
+
+
+
+ - org.lineageos.settings.device.KeyHandler
+
+
diff --git a/rootdir/etc/init.qcom.rc b/rootdir/etc/init.qcom.rc
index 4ca5a18..9838bc3 100644
--- a/rootdir/etc/init.qcom.rc
+++ b/rootdir/etc/init.qcom.rc
@@ -200,17 +200,29 @@ on boot
chown system system /sys/homebutton/enable
chown system system /sys/homebutton/enable_off
chown system system /sys/homebutton/haptic
+ chown system system /sys/homebutton/haptic_off
chown system system /sys/homebutton/key
chown system system /sys/homebutton/key_hold
- chown system system /sys/homebutton/key_up
- chown system system /sys/homebutton/key_down
chown system system /sys/homebutton/key_dbltap
chown system system /sys/homebutton/key_left
chown system system /sys/homebutton/key_right
+ chown system system /sys/homebutton/key_screenoff
+ chown system system /sys/homebutton/key_screenoff_hold
+ chown system system /sys/homebutton/key_screenoff_dbltap
+ chown system system /sys/homebutton/key_screenoff_left
+ chown system system /sys/homebutton/key_screenoff_right
- # Wake Gestures
+ # Screen off Gestures
chown system radio /sys/android_touch/doubletap2wake
chmod 0660 /sys/android_touch/doubletap2wake
+ chown system radio /sys/android_touch/gesture_swipe_right
+ chmod 0660 /sys/android_touch/gesture_swipe_right
+ chown system radio /sys/android_touch/gesture_swipe_left
+ chmod 0660 /sys/android_touch/gesture_swipe_left
+ chown system radio /sys/android_touch/gesture_swipe_down
+ chmod 0660 /sys/android_touch/gesture_swipe_down
+ chown system radio /sys/android_touch/gesture_swipe_up
+ chmod 0660 /sys/android_touch/gesture_swipe_up
# Display
chown system graphics /sys/class/graphics/fb1/hpd
@@ -853,7 +865,7 @@ on property:sys.boot_completed=1
# Apply inter-cluster load balancer restrictions
write /proc/sys/kernel/sched_restrict_cluster_spill 1
-
+
# set sync wakee policy tunable
write /proc/sys/kernel/sched_prefer_sync_wakee_to_waker 1
@@ -872,7 +884,7 @@ on property:sys.boot_completed=1
write /sys/class/devfreq/soc:qcom,cpubw/bw_hwmon/up_scale 250
write /sys/class/devfreq/soc:qcom,cpubw/min_freq 1611
write /sys/class/devfreq/soc:qcom,gpubw/bw_hwmon/io_percent 40
-
+
# disable thermal & BCL core_control to update interactive gov settings
write /sys/module/msm_thermal/core_control/enabled 0
write /sys/devices/soc/soc:qcom,bcl/mode "disable"