Android13锁屏或灭屏状态下,快速按两次音量下键实现打开闪光灯功能

实现思路:

1、发送广播

    WindowManagerService循环读取下面按键消息并分发给窗口,在消息分发前会在PhoneWindowManager.interceptKeyBeforeQueueing方法中进行消息的过滤。因此该实现方式为在消息分发前的interceptKeyBeforeQueueing方法中监听当前按键为音量下键,如果当前状态为锁屏状态,并按键为音量下键,且两次按键间隔时间小于800ms时发送广播--“com.custom.volume_down”

具体实现方式如下:

sys\frameworks\base\services\core\java\com\android\server\policy\PhoneWindowManager.java

private long lastTime = 0;

@Override
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
    final int keyCode = event.getKeyCode();
    final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;

    ......
    switch (keyCode) {
        ......
        case KeyEvent.KEYCODE_VOLUME_DOWN:
            // add start
            String volume_down = SystemProperties.get("persist.sys.double.volume_down");
            if (DEBUG_INPUT) {
                Log.i(TAG, "interceptKeyBeforeQueueing:"
                                          + " VOLUME KEYCODE_VOLUME_DOWN"
                                          + " volume_down = " + volume_down
                                          + " keyguardActive = " + keyguardActive
                                          + " lastTime = " + lastTime
                              );
            }
            if (down) { //按键按下
                if (volume_down != null && !volume_down.equals("0")) {
                    if (keyguardActive) {//锁屏
                        if (System.currentTimeMillis() - lastTime <= 800) {
                            mContext.sendBroadcast(new Intent("com.custom.volume_down"));
                        lastTime = 0;
                        } else {
                                lastTime = System.currentTimeMillis();
                        }
                        return 0;
                    }
                }
            }
        // add end
    case KeyEvent.KEYCODE_VOLUME_UP:
    ......

2、接收广播

接收到广播“com.custom.volume_down”后打开或关闭闪光灯

private CameraManager mCameraManager;
private boolean mFlashlightEnabled = false;

private String mCameraId;
private Handler mHandler;
private void initBroadcastReceiver(Context context) {
    mCameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
    tryInitCamera();
    IntentFilter filter = new IntentFilter();
    filter.addAction("com.custom.volume_down");
    context.registerReceiver(new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            LogUtils.i(TAG, "action = " + action);
            if (action != null) {
                if (action.equals("com.custom.volume_down")) {
                    String volume_down =     SysProUtils.get("persist.sys.double.volume_down");
                    LogUtils.i(TAG, "volume_down = " + volume_down);
                    if (volume_down != null) {
                        if (volume_down.equals("1")) {
                            setFlashlight(!mFlashlightEnabled);
                        }
                    }
                }
            }
        }
    }, filter);
}

private synchronized void ensureHandler() {
    if (mHandler == null) {
        HandlerThread thread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND);
        thread.start();
        mHandler = new Handler(thread.getLooper());
    }
}

public void setFlashlight(boolean enabled) {
    synchronized (this) {
        if (mCameraId == null) return;
        if (mFlashlightEnabled != enabled) {
            mFlashlightEnabled = enabled;
            try {
                mCameraManager.setTorchMode(mCameraId, enabled);
            } catch (CameraAccessException e) {
                Log.e(TAG, "Couldn't set torch mode", e);
                mFlashlightEnabled = false;
            }
        }
    }
}

private String getCameraId() throws CameraAccessException {
    String[] ids = mCameraManager.getCameraIdList();
    for (String id : ids) {
        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) {
            return id;
        }
    }
    return null;
}

private void tryInitCamera() {
    try {
        mCameraId = getCameraId();
    } catch (Throwable e) {
        Log.e(TAG, "Couldn't initialize.", e);
        return;
    }

    if (mCameraId != null) {
        ensureHandler();
        mCameraManager.registerTorchCallback(mTorchCallback, mHandler);
    }
}

private final CameraManager.TorchCallback mTorchCallback =
        new CameraManager.TorchCallback() {

            @Override
            @WorkerThread
            public void onTorchModeChanged(String cameraId, boolean enabled) {
                if (TextUtils.equals(cameraId, mCameraId)) {
                    setTorchMode(enabled);
                }
            }
        };

private void setTorchMode(boolean enabled) {
    synchronized (CommModule.this) {
        mFlashlightEnabled = enabled;
    }
}

3、在settings源码中添加控制

在settings中添加开关按钮。

如果打开开关,双击音量下键,打开或关闭闪光灯。

如果关闭开关,双击音量下键,不做任何处理。

在res/xml/accessibility_settings.xml中添加

+        <SwitchPreference
+            android:key="accessibility_flashlight"
+            android:persistent="false"
+            android:icon="@drawable/ic_flashlight"
+            android:summary="@string/accessibility_settings_flashlight_summary"
+            android:title="@string/accessibility_settings_flashlight_preference_title"
+            settings:searchable="true"
+            settings:controller="com.android.settings.accessibility.FlashlightPreferenceController"/>

在app\src\main\java\com\android\settings\accessibility目录下新建FlashlightPreferenceController.java

package com.android.settings.accessibility;

import android.content.Context;
import android.os.SystemProperties;
import android.text.TextUtils;

import com.android.settings.R;
import com.android.settings.core.TogglePreferenceController;

/**
 * A toggle preference controller for audio description
 */
public class FlashlightPreferenceController extends TogglePreferenceController {

    static final String PREF_KEY = "accessibility_flashlight";

    public FlashlightPreferenceController(Context context, String preferenceKey) {
        super(context, preferenceKey);
    }

    @Override
    public boolean isChecked() {
        String volume_down = SystemProperties.get("persist.sys.double.volume_down");
        if (!TextUtils.isEmpty(volume_down)) {
            if (volume_down.equals("1")) {
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean setChecked(boolean isChecked) {
        SystemProperties.set("persist.sys.double.volume_down", isChecked ? "1" : "0");
        return true;
    }

    @Override
    public int getAvailabilityStatus() {
        String volume_down = SystemProperties.get("persist.sys.double.volume_down");
        return TextUtils.isEmpty(volume_down) ? UNSUPPORTED_ON_DEVICE : AVAILABLE;
    }

    @Override
    public int getSliceHighlightMenuRes() {
        return R.string.menu_key_accessibility;
    }
}

InputDispatcher拦截逻辑_interceptkeybeforequeueing-CSDN博客

Android事件拦截_interceptkeybeforequeueing-CSDN博客

  • 9
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值