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

Commit 0b611159 authored by beanstown106's avatar beanstown106 Committed by Michael Bestas
Browse files

Long-press power while display is off for torch

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
    (cherry picked from commit 604f00ce)

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

Change-Id: I49222892c8fbc8a63af580c763e8987b225b11d2
parent f77fff2e
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -28,4 +28,8 @@
    <!-- 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" />

</manifest>
+142 −3
Original line number Diff line number Diff line
@@ -124,8 +124,10 @@ import android.app.ActivityManager.StackId;
import android.app.ActivityManagerInternal;
import android.app.ActivityManagerInternal.SleepToken;
import android.app.ActivityThread;
import android.app.AlarmManager;
import android.app.AppOpsManager;
import android.app.IUiModeManager;
import android.app.PendingIntent;
import android.app.ProgressDialog;
import android.app.SearchManager;
import android.app.StatusBarManager;
@@ -150,6 +152,9 @@ import android.database.ContentObserver;
import android.graphics.PixelFormat;
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.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiPlaybackClient;
@@ -300,6 +305,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    static final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1;
    static final int LONG_PRESS_POWER_SHUT_OFF = 2;
    static final int LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM = 3;
    static final int LONG_PRESS_POWER_TORCH = 4;

    static final int LONG_PRESS_BACK_NOTHING = 0;
    static final int LONG_PRESS_BACK_GO_TO_VOICE_ASSIST = 1;
@@ -372,6 +378,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    private static final String SYSUI_SCREENSHOT_ERROR_RECEIVER =
            "com.android.systemui.screenshot.ScreenshotServiceErrorReceiver";

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

    /**
     * Keyguard stuff
     */
@@ -433,6 +442,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    AccessibilityManager mAccessibilityManager;
    BurnInProtectionHelper mBurnInProtectionHelper;
    AppOpsManager mAppOpsManager;
    AlarmManager mAlarmManager;
    private boolean mHasFeatureWatch;
    private boolean mHasFeatureLeanback;

@@ -765,6 +775,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;

@@ -844,12 +857,20 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    private static final int MSG_DISPATCH_BACK_KEY_TO_AUTOFILL = 24;
    private static final int MSG_SYSTEM_KEY_PRESS = 25;
    private static final int MSG_HANDLE_ALL_APPS = 26;
    private static final int MSG_TOGGLE_TORCH = 27;

    private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
    private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1;

    private LineageHardwareManager mLineageHardware;

    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) {
@@ -941,6 +962,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                case MSG_HANDLE_ALL_APPS:
                    launchAllAppsAction();
                    break;
                case MSG_TOGGLE_TORCH:
                    toggleTorch();
                    break;
            }
        }
    }
@@ -999,6 +1023,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            resolver.registerContentObserver(LineageSettings.Global.getUriFor(
                    LineageSettings.Global.DEV_FORCE_SHOW_NAVBAR), 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();
        }

@@ -1343,21 +1373,26 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                // When interactive, we're already awake.
                // Wait for a long press or for the button to be released to decide what to do.
                if (hasLongPressOnPowerBehavior()) {
                    mResolvedLongPressOnPowerBehavior = getResolvedLongPressOnPowerBehavior();
                    Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
                    msg.setAsynchronous(true);
                    mHandler.sendMessageDelayed(msg,
                            ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
                }
            } else {
                wakeUpFromPowerKey(event.getDownTime());

                if (mSupportLongPressPowerWhenNonInteractive && hasLongPressOnPowerBehavior()) {
                    mResolvedLongPressOnPowerBehavior = getResolvedLongPressOnPowerBehavior();
                    if (mResolvedLongPressOnPowerBehavior != LONG_PRESS_POWER_TORCH) {
                        wakeUpFromPowerKey(event.getDownTime());
                    }
                    Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
                    msg.setAsynchronous(true);
                    mHandler.sendMessageDelayed(msg,
                            ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
                    mBeganFromNonInteractive = true;
                } else {
                    wakeUpFromPowerKey(event.getDownTime());

                    final int maxCount = getMaxMultiPressPowerCount();

                    if (maxCount <= 1) {
@@ -1416,6 +1451,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        if (!mPowerKeyHandled) {
            mPowerKeyHandled = true;
            mHandler.removeMessages(MSG_POWER_LONG_PRESS);
            // See if we deferred screen wake because long press power for torch is enabled
            if (mResolvedLongPressOnPowerBehavior == LONG_PRESS_POWER_TORCH && !isScreenOn()) {
                wakeUpFromPowerKey(SystemClock.uptimeMillis());
            }
        }
    }

@@ -1548,7 +1587,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    }

    private void powerLongPress() {
        final int behavior = getResolvedLongPressOnPowerBehavior();
        final int behavior = mResolvedLongPressOnPowerBehavior;
        switch (behavior) {
        case LONG_PRESS_POWER_NOTHING:
            break;
@@ -1564,6 +1603,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
            mWindowManagerFuncs.shutdown(behavior == LONG_PRESS_POWER_SHUT_OFF);
            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;
        }
    }

@@ -1615,6 +1663,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;
        }
        return mLongPressOnPowerBehavior;
    }

@@ -1892,6 +1943,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        mHasFeatureLeanback = mContext.getPackageManager().hasSystemFeature(FEATURE_LEANBACK);
        mAccessibilityShortcutController =
                new AccessibilityShortcutController(mContext, new Handler(), mCurrentUserId);
        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);

        // Init display burn-in protection
        boolean burnInProtectionEnabled = context.getResources().getBoolean(
                com.android.internal.R.bool.config_enableBurnInProtection);
@@ -1928,6 +1981,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        }

        mHandler = new PolicyHandler();
        mCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
        mCameraManager.registerTorchCallback(new TorchModeCallback(), mHandler);
        mWakeGestureListener = new MyWakeGestureListener(mContext, mHandler);
        mOrientationListener = new MyOrientationListener(mContext, mHandler);
        try {
@@ -2193,6 +2248,23 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            }
        }
        if (DEBUG) 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);
    }

    /**
@@ -2351,6 +2423,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                    Settings.Secure.INCALL_BACK_BUTTON_BEHAVIOR,
                    Settings.Secure.INCALL_BACK_BUTTON_BEHAVIOR_DEFAULT,
                    UserHandle.USER_CURRENT);
            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,
@@ -8640,4 +8718,65 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            mKeyguardDelegate.dump(prefix, pw);
        }
    }

    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, 0);
            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);
            int lensDirection = c.get(CameraCharacteristics.LENS_FACING);
            if (flashAvailable && lensDirection == CameraCharacteristics.LENS_FACING_BACK) {
                mRearFlashCameraId = id;
            }
        }
        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();
        }
    }
}