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

Commit e8faa41c authored by beanstown106's avatar beanstown106 Committed by Bruno Martins
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>

Change-Id: I49222892c8fbc8a63af580c763e8987b225b11d2
Signed-off-by: default avatarPranav Vashi <neobuddy89@gmail.com>
parent 7f3fda65
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -713,6 +713,11 @@
    <!-- Used to launch a common app (FlipFlap) for devices with flip cover. -->
    <protected-broadcast android:name="lineageos.intent.action.LID_STATE_CHANGED" />

    <!-- LineageOS additions -->

    <!-- 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
@@ -954,6 +954,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
@@ -126,7 +126,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
@@ -98,9 +98,11 @@ import android.annotation.Nullable;
import android.app.ActivityManager;
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;
@@ -121,6 +123,9 @@ import android.content.res.TypedArray;
import android.database.ContentObserver;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
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;
@@ -227,6 +232,8 @@ import com.android.server.wm.WindowManagerService;

import dalvik.system.PathClassLoader;

import lineageos.providers.LineageSettings;

import org.lineageos.internal.buttons.LineageButtons;

import java.io.File;
@@ -277,6 +284,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;
@@ -328,6 +336,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
            .build();

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

    /**
     * Keyguard stuff
     */
@@ -386,6 +397,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    AccessibilityManager mAccessibilityManager;
    BurnInProtectionHelper mBurnInProtectionHelper;
    private DisplayFoldController mDisplayFoldController;
    AlarmManager mAlarmManager;
    AppOpsManager mAppOpsManager;
    PackageManager mPackageManager;
    SideFpsEventHandler mSideFpsEventHandler;
@@ -565,6 +577,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;

@@ -634,6 +649,16 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    private static final int MSG_LAUNCH_ASSIST = 23;
    private static final int MSG_RINGER_TOGGLE_CHORD = 24;

    // 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) {
@@ -700,6 +725,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                case MSG_RINGER_TOGGLE_CHORD:
                    handleRingerChordGesture();
                    break;
                case MSG_TOGGLE_TORCH:
                    toggleTorch();
                    break;
            }
        }
    }
@@ -758,6 +786,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            resolver.registerContentObserver(Settings.Global.getUriFor(
                    Settings.Global.POWER_BUTTON_SUPPRESSION_DELAY_AFTER_GESTURE_WAKE), 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();
        }

@@ -901,9 +936,17 @@ 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.
            if (!mSingleKeyGestureDetector.isKeyIntercepted(KEYCODE_POWER)) {
@@ -919,6 +962,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());
                }
            }
        } else {
            // handled by single key or another power key policy.
@@ -1103,9 +1150,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:
@@ -1141,6 +1188,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;
        }
    }

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

        // If the config indicates the assistant behavior but the device isn't yet provisioned, show
        // global actions instead.
@@ -1693,6 +1752,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(context);
        mUiMode = context.getResources().getInteger(
                com.android.internal.R.integer.config_defaultUiModeType);
@@ -1885,6 +1950,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);
        context.registerReceiver(torchReceiver, filter);
    }

    private void initKeyCombinationRules() {
@@ -2150,6 +2232,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                mRingerToggleChord = Settings.Secure.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,
@@ -5520,6 +5609,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 ) {
@@ -5624,6 +5777,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);
        }