Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit c160ce02 authored by beanstown106's avatar beanstown106 Committed by Michael Bestas
Browse files

Long-press power while display is off for torch

Long-press the power button while the display is off
to turn the torchlight on and off.

Credits:
 - Lion0738: The main hooks here:
   https://github.com/lion0738/android_frameworks_base/commit/9af2b7844a4d973c8b6c542d7937f56a24a7e5f1


 - Atlantis: The logic on where to hook into this for power button only
 - Alex Cruz: Helping and giving me some pointers along the way

Co-authored-by: default avatarMichael Bestas <mkbestas@lineageos.org>
Co-authored-by: default avatarPranav Vashi <neobuddy89@gmail.com>
Co-authored-by: default avatarSam Mortimer <sam@mortimer.me.uk>
Change-Id: I1aaf8417b865df79e8a1a8d0039b3b860a46be78
parent 131cfacb
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -860,6 +860,9 @@
    <!-- Used to launch a common app (FlipFlap) for devices with flip cover. -->
    <!-- Used to launch a common app (FlipFlap) for devices with flip cover. -->
    <protected-broadcast android:name="lineageos.intent.action.LID_STATE_CHANGED" />
    <protected-broadcast android:name="lineageos.intent.action.LID_STATE_CHANGED" />


    <!-- Used for long press power torch feature - automatic turn off on timeout -->
    <protected-broadcast android:name="com.android.server.policy.PhoneWindowManager.ACTION_TORCH_OFF" />

    <!-- ====================================================================== -->
    <!-- ====================================================================== -->
    <!--                          RUNTIME PERMISSIONS                           -->
    <!--                          RUNTIME PERMISSIONS                           -->
    <!-- ====================================================================== -->
    <!-- ====================================================================== -->
+1 −0
Original line number Original line Diff line number Diff line
@@ -1155,6 +1155,7 @@
            3 - Power off (without confirmation)
            3 - Power off (without confirmation)
            4 - Go to voice assist
            4 - Go to voice assist
            5 - Go to assistant (Settings.Secure.ASSISTANT)
            5 - Go to assistant (Settings.Secure.ASSISTANT)
            6 - Toggle torch on / off (if screen is off)
    -->
    -->
    <integer name="config_longPressOnPowerBehavior">5</integer>
    <integer name="config_longPressOnPowerBehavior">5</integer>


+1 −1
Original line number Original line Diff line number Diff line
@@ -180,7 +180,7 @@ public class GlobalSettingsValidators {
        VALIDATORS.put(Global.POWER_BUTTON_SHORT_PRESS, new InclusiveIntegerRangeValidator(0, 8));
        VALIDATORS.put(Global.POWER_BUTTON_SHORT_PRESS, new InclusiveIntegerRangeValidator(0, 8));
        VALIDATORS.put(Global.POWER_BUTTON_DOUBLE_PRESS, new InclusiveIntegerRangeValidator(0, 3));
        VALIDATORS.put(Global.POWER_BUTTON_DOUBLE_PRESS, new InclusiveIntegerRangeValidator(0, 3));
        VALIDATORS.put(Global.POWER_BUTTON_TRIPLE_PRESS, new InclusiveIntegerRangeValidator(0, 3));
        VALIDATORS.put(Global.POWER_BUTTON_TRIPLE_PRESS, new InclusiveIntegerRangeValidator(0, 3));
        VALIDATORS.put(Global.POWER_BUTTON_LONG_PRESS, new InclusiveIntegerRangeValidator(0, 5));
        VALIDATORS.put(Global.POWER_BUTTON_LONG_PRESS, new InclusiveIntegerRangeValidator(0, 6));
        VALIDATORS.put(
        VALIDATORS.put(
                Global.POWER_BUTTON_VERY_LONG_PRESS, new InclusiveIntegerRangeValidator(0, 1));
                Global.POWER_BUTTON_VERY_LONG_PRESS, new InclusiveIntegerRangeValidator(0, 1));
        VALIDATORS.put(Global.KEY_CHORD_POWER_VOLUME_UP, new InclusiveIntegerRangeValidator(0, 2));
        VALIDATORS.put(Global.KEY_CHORD_POWER_VOLUME_UP, new InclusiveIntegerRangeValidator(0, 2));
+167 −3
Original line number Original line Diff line number Diff line
@@ -124,10 +124,12 @@ import android.app.ActivityManager.RecentTaskInfo;
import android.app.ActivityManagerInternal;
import android.app.ActivityManagerInternal;
import android.app.ActivityTaskManager;
import android.app.ActivityTaskManager;
import android.app.ActivityTaskManager.RootTaskInfo;
import android.app.ActivityTaskManager.RootTaskInfo;
import android.app.AlarmManager;
import android.app.AppOpsManager;
import android.app.AppOpsManager;
import android.app.IActivityManager;
import android.app.IActivityManager;
import android.app.IUiModeManager;
import android.app.IUiModeManager;
import android.app.NotificationManager;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.ProgressDialog;
import android.app.ProgressDialog;
import android.app.SearchManager;
import android.app.SearchManager;
import android.app.UiModeManager;
import android.app.UiModeManager;
@@ -148,6 +150,9 @@ import android.content.res.Resources;
import android.database.ContentObserver;
import android.database.ContentObserver;
import android.graphics.Rect;
import android.graphics.Rect;
import android.hardware.SensorPrivacyManager;
import android.hardware.SensorPrivacyManager;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraManager;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.hdmi.HdmiAudioSystemClient;
import android.hardware.hdmi.HdmiAudioSystemClient;
@@ -267,6 +272,8 @@ import com.android.server.wm.WindowManagerInternal.AppTransitionListener;


import dalvik.system.PathClassLoader;
import dalvik.system.PathClassLoader;


import lineageos.providers.LineageSettings;

import org.lineageos.internal.buttons.LineageButtons;
import org.lineageos.internal.buttons.LineageButtons;


import java.io.File;
import java.io.File;
@@ -329,6 +336,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    static final int LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM = 3;
    static final int LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM = 3;
    static final int LONG_PRESS_POWER_GO_TO_VOICE_ASSIST = 4;
    static final int LONG_PRESS_POWER_GO_TO_VOICE_ASSIST = 4;
    static final int LONG_PRESS_POWER_ASSISTANT = 5; // Settings.Secure.ASSISTANT
    static final int LONG_PRESS_POWER_ASSISTANT = 5; // Settings.Secure.ASSISTANT
    static final int LONG_PRESS_POWER_TORCH = 6;


    // must match: config_veryLongPresOnPowerBehavior in config.xml
    // must match: config_veryLongPresOnPowerBehavior in config.xml
    // The config value can be overridden using Settings.Global.POWER_BUTTON_VERY_LONG_PRESS
    // The config value can be overridden using Settings.Global.POWER_BUTTON_VERY_LONG_PRESS
@@ -423,6 +431,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {


    private static final int POWER_BUTTON_SUPPRESSION_DELAY_DEFAULT_MILLIS = 800;
    private static final int POWER_BUTTON_SUPPRESSION_DELAY_DEFAULT_MILLIS = 800;


    private static final String ACTION_TORCH_OFF =
            "com.android.server.policy.PhoneWindowManager.ACTION_TORCH_OFF";

    /**
    /**
     * Keyguard stuff
     * Keyguard stuff
     */
     */
@@ -503,6 +514,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    AccessibilityManagerInternal mAccessibilityManagerInternal;
    AccessibilityManagerInternal mAccessibilityManagerInternal;
    BurnInProtectionHelper mBurnInProtectionHelper;
    BurnInProtectionHelper mBurnInProtectionHelper;
    private DisplayFoldController mDisplayFoldController;
    private DisplayFoldController mDisplayFoldController;
    AlarmManager mAlarmManager;
    AppOpsManager mAppOpsManager;
    AppOpsManager mAppOpsManager;
    PackageManager mPackageManager;
    PackageManager mPackageManager;
    SideFpsEventHandler mSideFpsEventHandler;
    SideFpsEventHandler mSideFpsEventHandler;
@@ -711,6 +723,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    // behavior will be skipped if the default display is non-interactive.
    // behavior will be skipped if the default display is non-interactive.
    private boolean mSupportShortPressPowerWhenDefaultDisplayOn;
    private boolean mSupportShortPressPowerWhenDefaultDisplayOn;


    // Power long press action saved on key down that should happen on key up
    private int mResolvedLongPressOnPowerBehavior;

    // Whether to go to sleep entering theater mode from power button
    // Whether to go to sleep entering theater mode from power button
    private boolean mGoToSleepOnButtonPressTheaterMode;
    private boolean mGoToSleepOnButtonPressTheaterMode;


@@ -788,6 +803,16 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 25;
    private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 25;
    private static final int MSG_SET_DEFERRED_KEY_ACTIONS_EXECUTABLE = 27;
    private static final int MSG_SET_DEFERRED_KEY_ACTIONS_EXECUTABLE = 27;


    // Lineage additions
    private static final int MSG_TOGGLE_TORCH = 100;

    private CameraManager mCameraManager;
    private String mRearFlashCameraId;
    private boolean mTorchLongPressPowerEnabled;
    private boolean mTorchEnabled;
    private int mTorchTimeout;
    private PendingIntent mTorchOffPendingIntent;

    private class PolicyHandler extends Handler {
    private class PolicyHandler extends Handler {


        private PolicyHandler(Looper looper) {
        private PolicyHandler(Looper looper) {
@@ -882,6 +907,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                    final long downTime = (Long) msg.obj;
                    final long downTime = (Long) msg.obj;
                    mDeferredKeyActionExecutor.setActionsExecutable(keyCode, downTime);
                    mDeferredKeyActionExecutor.setActionsExecutable(keyCode, downTime);
                    break;
                    break;
                case MSG_TOGGLE_TORCH:
                    toggleTorch();
                    break;
            }
            }
        }
        }
    }
    }
@@ -967,6 +995,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            resolver.registerContentObserver(Settings.Secure.getUriFor(
            resolver.registerContentObserver(Settings.Secure.getUriFor(
                    Settings.Secure.NAV_BAR_KIDS_MODE), false, this,
                    Settings.Secure.NAV_BAR_KIDS_MODE), false, this,
                    UserHandle.USER_ALL);
                    UserHandle.USER_ALL);
            resolver.registerContentObserver(LineageSettings.System.getUriFor(
                    LineageSettings.System.TORCH_LONG_PRESS_POWER_GESTURE), false, this,
                    UserHandle.USER_ALL);
            resolver.registerContentObserver(LineageSettings.System.getUriFor(
                    LineageSettings.System.TORCH_LONG_PRESS_POWER_TIMEOUT), false, this,
                    UserHandle.USER_ALL);
            updateSettings();
            updateSettings();
        }
        }


@@ -1123,8 +1157,16 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                || mKeyCombinationManager.isPowerKeyIntercepted();
                || mKeyCombinationManager.isPowerKeyIntercepted();


        if (!mPowerKeyHandled) {
        if (!mPowerKeyHandled) {
            mResolvedLongPressOnPowerBehavior = getResolvedLongPressOnPowerBehavior();
            if (!interactive) {
            if (!interactive) {
                if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
                    wakeUpFromWakeKey(event);
                    wakeUpFromWakeKey(event);
                } else if (mSupportLongPressPowerWhenNonInteractive &&
                        hasLongPressOnPowerBehavior()) {
                    if (mResolvedLongPressOnPowerBehavior != LONG_PRESS_POWER_TORCH) {
                        wakeUpFromWakeKey(event);
                    }
                }
            }
            }
        } else {
        } else {
            // handled by another power key policy.
            // handled by another power key policy.
@@ -1138,6 +1180,20 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    private void interceptPowerKeyUp(KeyEvent event, boolean canceled) {
    private void interceptPowerKeyUp(KeyEvent event, boolean canceled) {
        // Inform the StatusBar; but do not allow it to consume the event.
        // Inform the StatusBar; but do not allow it to consume the event.
        sendSystemKeyToStatusBarAsync(event);
        sendSystemKeyToStatusBarAsync(event);

        final boolean handled = canceled || mPowerKeyHandled;

        if (!handled) {
            if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) == 0) {
                // Abort possibly stuck animations only when power key up without long press case.
                mHandler.post(mWindowManagerFuncs::triggerAnimationFailsafe);
                // See if we deferred screen wake because long press power for torch is enabled
                if (mResolvedLongPressOnPowerBehavior == LONG_PRESS_POWER_TORCH && !isScreenOn()) {
                    wakeUpFromWakeKey(event);
                }
            }
        }

        finishPowerKeyPress();
        finishPowerKeyPress();
    }
    }


@@ -1511,9 +1567,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    }
    }


    private void powerLongPress(long eventTime) {
    private void powerLongPress(long eventTime) {
        final int behavior = getResolvedLongPressOnPowerBehavior();
        final int behavior = mResolvedLongPressOnPowerBehavior;
        Slog.d(TAG, "powerLongPress: eventTime=" + eventTime
        Slog.d(TAG, "powerLongPress: eventTime=" + eventTime
                + " mLongPressOnPowerBehavior=" + mLongPressOnPowerBehavior);
                + " mResolvedLongPressOnPowerBehavior=" + mResolvedLongPressOnPowerBehavior);


        // Sending a synthetic KeyEvent to StatusBar service with flag FLAG_LONG_PRESS set, when
        // Sending a synthetic KeyEvent to StatusBar service with flag FLAG_LONG_PRESS set, when
        // power button is long pressed
        // power button is long pressed
@@ -1568,6 +1624,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                launchAssistAction(null, powerKeyDeviceId, eventTime,
                launchAssistAction(null, powerKeyDeviceId, eventTime,
                        AssistUtils.INVOCATION_TYPE_POWER_BUTTON_LONG_PRESS);
                        AssistUtils.INVOCATION_TYPE_POWER_BUTTON_LONG_PRESS);
                break;
                break;
            case LONG_PRESS_POWER_TORCH:
                mPowerKeyHandled = true;
                // Toggle torch state asynchronously to help protect against
                // a misbehaving cameraservice from blocking systemui.
                mHandler.removeMessages(MSG_TOGGLE_TORCH);
                Message msg = mHandler.obtainMessage(MSG_TOGGLE_TORCH);
                msg.setAsynchronous(true);
                msg.sendToTarget();
                break;
        }
        }
    }
    }


@@ -1634,6 +1699,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        if (FactoryTest.isLongPressOnPowerOffEnabled()) {
        if (FactoryTest.isLongPressOnPowerOffEnabled()) {
            return LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM;
            return LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM;
        }
        }
        if (mTorchLongPressPowerEnabled && (!isScreenOn() || mTorchEnabled)) {
            return LONG_PRESS_POWER_TORCH;
        }


        // If the config indicates the assistant behavior but the device isn't yet provisioned, show
        // If the config indicates the assistant behavior but the device isn't yet provisioned, show
        // global actions instead.
        // global actions instead.
@@ -2452,6 +2520,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        mWakeGestureListener = new MyWakeGestureListener(mContext, mHandler);
        mWakeGestureListener = new MyWakeGestureListener(mContext, mHandler);
        mSettingsObserver = new SettingsObserver(mHandler);
        mSettingsObserver = new SettingsObserver(mHandler);
        mSettingsObserver.observe();
        mSettingsObserver.observe();

        // Lineage additions
        mAlarmManager = mContext.getSystemService(AlarmManager.class);
        mCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
        mCameraManager.registerTorchCallback(new TorchModeCallback(), mHandler);

        mModifierShortcutManager = new ModifierShortcutManager(
        mModifierShortcutManager = new ModifierShortcutManager(
                mContext, mHandler, UserHandle.of(mCurrentUserId));
                mContext, mHandler, UserHandle.of(mCurrentUserId));
        mUiMode = mContext.getResources().getInteger(
        mUiMode = mContext.getResources().getInteger(
@@ -2640,6 +2714,23 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        if (DEBUG_INPUT) {
        if (DEBUG_INPUT) {
            Slog.d(TAG, "" + mDeviceKeyHandlers.size() + " device key handlers loaded");
            Slog.d(TAG, "" + mDeviceKeyHandlers.size() + " device key handlers loaded");
        }
        }

        // Register for torch off events
        BroadcastReceiver torchReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                mTorchOffPendingIntent = null;
                if (mTorchEnabled) {
                    mHandler.removeMessages(MSG_TOGGLE_TORCH);
                    Message msg = mHandler.obtainMessage(MSG_TOGGLE_TORCH);
                    msg.setAsynchronous(true);
                    msg.sendToTarget();
                }
            }
        };
        filter = new IntentFilter();
        filter.addAction(ACTION_TORCH_OFF);
        mContext.registerReceiver(torchReceiver, filter);
    }
    }


    private void initKeyCombinationRules() {
    private void initKeyCombinationRules() {
@@ -3143,6 +3234,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                mRingerToggleChord = VOLUME_HUSH_OFF;
                mRingerToggleChord = VOLUME_HUSH_OFF;
            }
            }


            mTorchLongPressPowerEnabled = LineageSettings.System.getIntForUser(
                    resolver, LineageSettings.System.TORCH_LONG_PRESS_POWER_GESTURE, 0,
                    UserHandle.USER_CURRENT) == 1;
            mTorchTimeout = LineageSettings.System.getIntForUser(
                    resolver, LineageSettings.System.TORCH_LONG_PRESS_POWER_TIMEOUT, 0,
                    UserHandle.USER_CURRENT);

            // Configure wake gesture.
            // Configure wake gesture.
            boolean wakeGestureEnabledSetting = Settings.Secure.getIntForUser(resolver,
            boolean wakeGestureEnabledSetting = Settings.Secure.getIntForUser(resolver,
                    Settings.Secure.WAKE_GESTURE_ENABLED, 0,
                    Settings.Secure.WAKE_GESTURE_ENABLED, 0,
@@ -7366,6 +7464,70 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        }
        }
    }
    }


    private void cancelTorchOff() {
        if (mTorchOffPendingIntent != null) {
            mAlarmManager.cancel(mTorchOffPendingIntent);
            mTorchOffPendingIntent = null;
        }
    }

    private void toggleTorch() {
        cancelTorchOff();
        final boolean origEnabled = mTorchEnabled;
        try {
            final String rearFlashCameraId = getRearFlashCameraId();
            if (rearFlashCameraId != null) {
                mCameraManager.setTorchMode(rearFlashCameraId, !mTorchEnabled);
                mTorchEnabled = !mTorchEnabled;
            }
        } catch (CameraAccessException e) {
            // Ignore
        }
        // Setup torch off alarm
        if (mTorchEnabled && !origEnabled && mTorchTimeout > 0) {
            Intent torchOff = new Intent(ACTION_TORCH_OFF);
            torchOff.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
                    | Intent.FLAG_RECEIVER_FOREGROUND);
            mTorchOffPendingIntent = PendingIntent.getBroadcast(mContext, 0, torchOff,
                    PendingIntent.FLAG_IMMUTABLE);
            mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                    SystemClock.elapsedRealtime() + mTorchTimeout * 1000, mTorchOffPendingIntent);
        }
    }

    private String getRearFlashCameraId() throws CameraAccessException {
        if (mRearFlashCameraId != null) return mRearFlashCameraId;
        for (final String id : mCameraManager.getCameraIdList()) {
            CameraCharacteristics c = mCameraManager.getCameraCharacteristics(id);
            Boolean flashAvailable = c.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
            Integer lensFacing = c.get(CameraCharacteristics.LENS_FACING);
            if (flashAvailable != null && flashAvailable
                    && lensFacing != null && lensFacing == CameraCharacteristics.LENS_FACING_BACK) {
                mRearFlashCameraId = id;
                break;
            }
        }
        return mRearFlashCameraId;
    }

    private class TorchModeCallback extends CameraManager.TorchCallback {
        @Override
        public void onTorchModeChanged(String cameraId, boolean enabled) {
            if (!cameraId.equals(mRearFlashCameraId)) return;
            mTorchEnabled = enabled;
            if (!mTorchEnabled) {
                cancelTorchOff();
            }
        }

        @Override
        public void onTorchModeUnavailable(String cameraId) {
            if (!cameraId.equals(mRearFlashCameraId)) return;
            mTorchEnabled = false;
            cancelTorchOff();
        }
    }

    private static String endcallBehaviorToString(int behavior) {
    private static String endcallBehaviorToString(int behavior) {
        StringBuilder sb = new StringBuilder();
        StringBuilder sb = new StringBuilder();
        if ((behavior & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0 ) {
        if ((behavior & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0 ) {
@@ -7472,6 +7634,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                return "LONG_PRESS_POWER_GO_TO_VOICE_ASSIST";
                return "LONG_PRESS_POWER_GO_TO_VOICE_ASSIST";
            case LONG_PRESS_POWER_ASSISTANT:
            case LONG_PRESS_POWER_ASSISTANT:
                return "LONG_PRESS_POWER_ASSISTANT";
                return "LONG_PRESS_POWER_ASSISTANT";
            case LONG_PRESS_POWER_TORCH:
                return "LONG_PRESS_POWER_TORCH";
            default:
            default:
                return Integer.toString(behavior);
                return Integer.toString(behavior);
        }
        }