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

Commit 5766edaf authored by jt1134's avatar jt1134
Browse files

LockScreen: allow long-press actions from hardware keys (1/2)

Allow following actions with button long-presses on lockscreen:
- toggle flashlight (if available)
- play/pause/next/previous track selection
- toggle silent mode

Allow customizing of back, menu, and home buttons. Search
button events are completely ignored on the lockscreen.

Auto-detect hardware keys, only show appropriate menu
options based on the actual hardware keys available on the
device (or completely hide if there are no hardware keys).

Based largely on Danny Baumann's work from gingerbread.

Ported from CM10

Change-Id: Iff32736d00ca5d4122f64a6a861bbb0a1de9cca9
parent b055725d
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -2828,6 +2828,23 @@ public final class Settings {
         */
        public static final String LOCKSCREEN_BACKGROUND = "lockscreen_background";

         /**
         * Action for long-pressing back button on lock screen
         * @hide
         */
        public static final String LOCKSCREEN_LONG_BACK_ACTION = "lockscreen_long_back_action";

        /**
         * Action for long-pressing home button on lock screen
         * @hide
         */
        public static final String LOCKSCREEN_LONG_HOME_ACTION = "lockscreen_long_home_action";

        /**
         * Action for long-pressing menu button on lock screen
         * @hide
         */
        public static final String LOCKSCREEN_LONG_MENU_ACTION = "lockscreen_long_menu_action";

        /**
         * Show the pending notification counts as overlays on the status bar
+118 −6
Original line number Diff line number Diff line
@@ -20,14 +20,19 @@ import android.app.Activity;
import android.app.ActivityManager;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.media.AudioManager;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcelable;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.Vibrator;
import android.provider.Settings;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
@@ -141,18 +146,125 @@ public class KeyguardViewManager {
        public boolean dispatchKeyEvent(KeyEvent event) {
            if (event.getAction() == KeyEvent.ACTION_DOWN && mKeyguardView != null) {
                int keyCode = event.getKeyCode();
                if (keyCode == KeyEvent.KEYCODE_BACK && mKeyguardView.handleBackKey()) {
                String action = null;
                switch (keyCode) {
                    case KeyEvent.KEYCODE_BACK:
                        if (mKeyguardView.handleBackKey()) {
                            return true;
                } else if (keyCode == KeyEvent.KEYCODE_MENU && mKeyguardView.handleMenuKey()) {
                        }
                        if (event.isLongPress()) {
                            action = Settings.System.LOCKSCREEN_LONG_BACK_ACTION;
                        }
                        break;
                    case KeyEvent.KEYCODE_HOME:
                        if (mKeyguardView.handleHomeKey()) {
                            return true;
                } else if (keyCode == KeyEvent.KEYCODE_HOME && mKeyguardView.handleHomeKey()) {
                        }
                        if (event.isLongPress()) {
                            action = Settings.System.LOCKSCREEN_LONG_HOME_ACTION;
                        }
                        break;
                    case KeyEvent.KEYCODE_MENU:
                        if (mKeyguardView.handleMenuKey()) {
                            return true;
                        }
                        if (event.isLongPress()) {
                            action = Settings.System.LOCKSCREEN_LONG_MENU_ACTION;
                        }
                        break;
                }

                if (action != null) {
                    String uri = Settings.System.getString(mContext.getContentResolver(), action);
                    if (uri != null && runAction(mContext, uri) != ACTION_RESULT_NOTRUN) {
                        long[] pattern = getLongPressVibePattern(mContext);
                        if (pattern != null) {
                            Vibrator v = (Vibrator) mContext.getSystemService(mContext.VIBRATOR_SERVICE);
                            if (pattern.length == 1) {
                                v.vibrate(pattern[0]);
                            } else {
                                v.vibrate(pattern, -1);
                            }
                        }
                        return true;
                    }
                }
            }
            return super.dispatchKeyEvent(event);
        }
    }

    private static final int ACTION_RESULT_RUN = 0;
    private static final int ACTION_RESULT_NOTRUN = 1;

    private static int runAction(Context context, String uri) {
        if ("FLASHLIGHT".equals(uri)) {
            context.sendBroadcast(new Intent("net.cactii.flash2.TOGGLE_FLASHLIGHT"));
            return ACTION_RESULT_RUN;
        } else if ("NEXT".equals(uri)) {
            sendMediaButtonEvent(context, KeyEvent.KEYCODE_MEDIA_NEXT);
            return ACTION_RESULT_RUN;
        } else if ("PREVIOUS".equals(uri)) {
            sendMediaButtonEvent(context, KeyEvent.KEYCODE_MEDIA_PREVIOUS);
            return ACTION_RESULT_RUN;
        } else if ("PLAYPAUSE".equals(uri)) {
            sendMediaButtonEvent(context, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
            return ACTION_RESULT_RUN;
        } else if ("SOUND".equals(uri)) {
            toggleSilentMode(context);
            return ACTION_RESULT_RUN;
        }

        return ACTION_RESULT_NOTRUN;
    }

    private static void sendMediaButtonEvent(Context context, int code) {
        long eventtime = SystemClock.uptimeMillis();

        Intent downIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
        KeyEvent downEvent = new KeyEvent(eventtime, eventtime, KeyEvent.ACTION_DOWN, code, 0);
        downIntent.putExtra(Intent.EXTRA_KEY_EVENT, downEvent);
        context.sendOrderedBroadcast(downIntent, null);

        Intent upIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
        KeyEvent upEvent = new KeyEvent(eventtime, eventtime, KeyEvent.ACTION_UP, code, 0);
        upIntent.putExtra(Intent.EXTRA_KEY_EVENT, upEvent);
        context.sendOrderedBroadcast(upIntent, null);
    }

    private static void toggleSilentMode(Context context) {
        final AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
        final Vibrator vib = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
        final boolean hasVib = vib == null ? false : vib.hasVibrator();
        if (am.getRingerMode() == AudioManager.RINGER_MODE_NORMAL) {
            am.setRingerMode(hasVib
                ? AudioManager.RINGER_MODE_VIBRATE
                : AudioManager.RINGER_MODE_SILENT);
        } else {
            am.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
        }
    }

    private static long[] getLongPressVibePattern(Context context) {
        if (Settings.System.getInt(context.getContentResolver(),
                Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) == 0) {
            return null;
        }

        int[] defaultPattern = context.getResources().getIntArray(
                com.android.internal.R.array.config_longPressVibePattern);
        if (defaultPattern == null) {
            return null;
        }

        long[] pattern = new long[defaultPattern.length];
        for (int i = 0; i < defaultPattern.length; i++) {
            pattern[i] = defaultPattern[i];
        }

        return pattern;
    }

    SparseArray<Parcelable> mStateContainer = new SparseArray<Parcelable>();

    private void maybeCreateKeyguardLocked(boolean enableScreenRotation, boolean force,