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

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

Long-press power while display is off for torch

Fixups for twelve (neobuddy89)
Fixups for ten (sam3000)

Squash of:

Author: beanstown106 <nbenis106@gmail.com>
Date:   Sun Jan 17 09:14:19 2016 -0500
    policy: 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

    Change-Id: I14365389990eb06daaa127f5db66df45abf6c064

Author: Sam Mortimer <sam@mortimer.me.uk>
Date:   Sat Dec 24 13:22:53 2016 -0800
    [1/3] Torch long press power: add auto-off function

    Change-Id: Icdf50082324f8292859f0df8b271e730b02c84e7

Author: Pranav Vashi <neobuddy89@gmail.com>
Date:   Fri Dec 3 08:53:59 2021 +0530
    Fix long-press power for torch on Android S

    * We must define FLAG_IMMUTABLE when creating PendingIntent on Android S

    Signed-off-by: default avatarPranav Vashi <neobuddy89@gmail.com>

Author: Sam Mortimer <sam@mortimer.me.uk>
Date:   Tue Jan 28 00:47:27 2020 -0800
    fw/b torch: Let long press power turn torch off when screen is on.

    * When the torch is on, any subsequent long press power is almost certainly
      intended to turn the torch off (regardless of screen state).  Therefore,
      always allow long press power to toggle torch if the torch is on.

    * Tested: long press power toggles torch on/off with screen off.
              long press power toggles torch off with screen on and torch on.
              long press power brings up global actions menu with screen on and torch off.

    Change-Id: I932caa9f3be06d14408aea2ecb3a6eca73e052e0

Change-Id: I1aaf8417b865df79e8a1a8d0039b3b860a46be78
parent ee427ff0
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -834,6 +834,9 @@
    <!-- Used to launch a common app (FlipFlap) for devices with flip cover. -->
    <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                           -->
    <!-- ====================================================================== -->
+1 −0
Original line number Diff line number Diff line
@@ -1096,6 +1096,7 @@
            3 - Power off (without confirmation)
            4 - Go to voice assist
            5 - Go to assistant (Settings.Secure.ASSISTANT)
            6 - Toggle torch on / off (if screen is off)
    -->
    <integer name="config_longPressOnPowerBehavior">5</integer>

+1 −1
Original line number Diff line number Diff line
@@ -176,7 +176,7 @@ public class GlobalSettingsValidators {
        VALIDATORS.put(Global.REQUIRE_PASSWORD_TO_DECRYPT, BOOLEAN_VALIDATOR);
        VALIDATORS.put(Global.DEVICE_DEMO_MODE, BOOLEAN_VALIDATOR);
        VALIDATORS.put(Global.AWARE_ALLOWED, BOOLEAN_VALIDATOR);
        VALIDATORS.put(Global.POWER_BUTTON_LONG_PRESS, new InclusiveIntegerRangeValidator(0, 5));
        VALIDATORS.put(Global.POWER_BUTTON_LONG_PRESS, new InclusiveIntegerRangeValidator(0, 6));
        VALIDATORS.put(
                Global.POWER_BUTTON_VERY_LONG_PRESS, new InclusiveIntegerRangeValidator(0, 1));
        VALIDATORS.put(Global.KEY_CHORD_POWER_VOLUME_UP, new InclusiveIntegerRangeValidator(0, 2));
+158 −3
Original line number Diff line number Diff line
@@ -96,9 +96,11 @@ import android.app.ActivityManager;
import android.app.ActivityManager.RecentTaskInfo;
import android.app.ActivityManagerInternal;
import android.app.ActivityTaskManager;
import android.app.AlarmManager;
import android.app.AppOpsManager;
import android.app.IUiModeManager;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.ProgressDialog;
import android.app.SearchManager;
import android.app.UiModeManager;
@@ -119,6 +121,9 @@ import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Rect;
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.DisplayManagerInternal;
import android.hardware.hdmi.HdmiAudioSystemClient;
@@ -238,6 +243,8 @@ import com.android.server.wm.WindowManagerInternal.AppTransitionListener;

import dalvik.system.PathClassLoader;

import lineageos.providers.LineageSettings;

import org.lineageos.internal.buttons.LineageButtons;

import java.io.File;
@@ -290,6 +297,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    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_ASSISTANT = 5; // Settings.Secure.ASSISTANT
    static final int LONG_PRESS_POWER_TORCH = 6;

    // must match: config_veryLongPresOnPowerBehavior in config.xml
    static final int VERY_LONG_PRESS_POWER_NOTHING = 0;
@@ -370,6 +378,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    private static final VibrationAttributes HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES =
            VibrationAttributes.createForUsage(VibrationAttributes.USAGE_HARDWARE_FEEDBACK);

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

    /**
     * Keyguard stuff
     */
@@ -439,6 +450,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    AccessibilityManagerInternal mAccessibilityManagerInternal;
    BurnInProtectionHelper mBurnInProtectionHelper;
    private DisplayFoldController mDisplayFoldController;
    AlarmManager mAlarmManager;
    AppOpsManager mAppOpsManager;
    PackageManager mPackageManager;
    SideFpsEventHandler mSideFpsEventHandler;
@@ -625,6 +637,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    // Whether to support long press from power button in non-interactive mode
    private boolean mSupportLongPressPowerWhenNonInteractive;

    // 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
    private boolean mGoToSleepOnButtonPressTheaterMode;

@@ -701,6 +716,16 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 25;
    private static final int MSG_LOG_KEYBOARD_SYSTEM_EVENT = 26;

    // 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 {
        @Override
        public void handleMessage(Message msg) {
@@ -779,6 +804,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                case MSG_LOG_KEYBOARD_SYSTEM_EVENT:
                    handleKeyboardSystemEvent(KeyboardLogEvent.from(msg.arg1), (KeyEvent) msg.obj);
                    break;
                case MSG_TOGGLE_TORCH:
                    toggleTorch();
                    break;
            }
        }
    }
@@ -840,6 +868,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            resolver.registerContentObserver(Settings.Secure.getUriFor(
                    Settings.Secure.STYLUS_BUTTONS_ENABLED), false, this,
                    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();
        }

@@ -991,8 +1026,16 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        mPowerKeyHandled = mPowerKeyHandled || hungUp
                || handledByPowerManager || mKeyCombinationManager.isPowerKeyIntercepted();
        if (!mPowerKeyHandled) {
            mResolvedLongPressOnPowerBehavior = getResolvedLongPressOnPowerBehavior();
            if (!interactive) {
                if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
                    wakeUpFromPowerKey(event.getDownTime());
                } else if (mSupportLongPressPowerWhenNonInteractive &&
                        hasLongPressOnPowerBehavior()) {
                    if (mResolvedLongPressOnPowerBehavior != LONG_PRESS_POWER_TORCH) {
                        wakeUpFromPowerKey(event.getDownTime());
                    }
                }
            }
        } else {
            // handled by another power key policy.
@@ -1010,6 +1053,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            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()) {
                    wakeUpFromPowerKey(SystemClock.uptimeMillis());
                }
            }
        }

@@ -1271,9 +1318,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    }

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

        switch (behavior) {
            case LONG_PRESS_POWER_NOTHING:
@@ -1314,6 +1361,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                launchAssistAction(null, powerKeyDeviceId, eventTime,
                        AssistUtils.INVOCATION_TYPE_POWER_BUTTON_LONG_PRESS);
                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;
        }
    }

@@ -1371,6 +1427,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        if (FactoryTest.isLongPressOnPowerOffEnabled()) {
            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
        // global actions instead.
@@ -2129,6 +2188,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        mWakeGestureListener = new MyWakeGestureListener(mContext, mHandler);
        mSettingsObserver = new SettingsObserver(mHandler);
        mSettingsObserver.observe();

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

        mModifierShortcutManager = new ModifierShortcutManager(mContext, mHandler);
        mUiMode = mContext.getResources().getInteger(
                com.android.internal.R.integer.config_defaultUiModeType);
@@ -2333,6 +2398,23 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        if (DEBUG_INPUT) {
            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() {
@@ -2680,6 +2762,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                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.
            boolean wakeGestureEnabledSetting = Settings.Secure.getIntForUser(resolver,
                    Settings.Secure.WAKE_GESTURE_ENABLED, 0,
@@ -6375,6 +6464,70 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        mHandler.getLooper().dump(new PrintWriterPrinter(pw), prefix + "  ");
    }

    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) {
        StringBuilder sb = new StringBuilder();
        if ((behavior & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0 ) {
@@ -6481,6 +6634,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                return "LONG_PRESS_POWER_GO_TO_VOICE_ASSIST";
            case LONG_PRESS_POWER_ASSISTANT:
                return "LONG_PRESS_POWER_ASSISTANT";
            case LONG_PRESS_POWER_TORCH:
                return "LONG_PRESS_POWER_TORCH";
            default:
                return Integer.toString(behavior);
        }