口袋模式的实现

口袋模式

口袋模式:带有黑屏手势功能的手机,一般都需要进行一个防误触的判断。防止手机放在口袋里或者包包(一些导电介质的东西可能带来辅助效果,比如钥匙)里别误触发点亮屏幕,甚至是打出电话。

口袋模式设计原理:接近式传感器的靠近与远离功能。可以参考我们手机打电话时,耳朵贴近手机的时候,往往屏幕是自动息屏,离开耳朵一小段距离,屏幕又亮起的这个功能。同理和我们放在口袋中一个意思。

概要设计

  1. 添加设置的各级菜单

  2. 获取距离传感器以及功能实现

功能实现

添加各级菜单

各级菜单的定义以及其界面的实现,主要是对交互界面的实现,除数据库的存储外,不涉及到逻辑的处理。

一、添加设置的各级菜单

添加模块:MtkSettings

添加菜单

路径: res/xml/gestures.xml

        <com.android.settingslib.PrimarySwitchPreference
​
            android:key="pocket_mode"
​
            android:title="@string/pocket_mode"
​
            android:summary="@string/pocket_mode_tip"
​
            settings:controller="com.android.settings.gestures.PocketModePreferenceController" />

添加字符串资源

路径:res/values/strings.xml

<string name="pocket_mode">Pocket Mode</string>
​
<string name="pocket_mode_tip">It can help users avoid accidental touch of the screen in their pockets or bags</string>
​

添加PocketModePreferenceController.java类

路径:这个类需要在gestures目录上自行添加。src/com/android/settings/gestures/PocketModePreferenceController.java

package com.android.settings.gestures;
import static android.provider.Settings.Secure.TURN_ON_BACKLIGHT_GESTURE;
import android.content.ContentResolver;
import android.content.Context;
import android.net.Uri;
import android.os.Handler;
import android.os.SystemProperties;
import android.provider.Settings;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.core.TogglePreferenceController;
import com.android.settingslib.PrimarySwitchPreference;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
import com.google.common.annotations.VisibleForTesting;
import java.io.DataOutputStream;
import java.io.IOException;
import android.database.ContentObserver;
​
public class PocketModePreferenceController extends TogglePreferenceController
        implements LifecycleObserver, OnStart, OnStop {
​
    @VisibleForTesting
    static final int KEY_CHORD_POWER_VOLUME_UP_MUTE_TOGGLE = 1;
​
    private Preference mPreference;
    private SettingObserver mSettingObserver;
​
    public PocketModePreferenceController(Context context, String preferenceKey) {
        super(context, preferenceKey);
    }
​
    @Override
    public void displayPreference(PreferenceScreen screen) {
        super.displayPreference(screen);
        mPreference = screen.findPreference(getPreferenceKey());
        mSettingObserver = new SettingObserver(mPreference);
    }
​
    @Override
    public boolean isChecked() {
        final int status = Settings.Secure.getInt(mContext.getContentResolver(),
                Settings.Secure.POCKET_MODE,0);
        return status != 0;
    }
​
    @Override
    public boolean setChecked(boolean isChecked) {
        return Settings.Secure.putInt(mContext.getContentResolver(),
                Settings.Secure.POCKET_MODE, isChecked ? 1 : 0);
    }
​
    @Override
    public void updateState(Preference preference) {
        super.updateState(preference);
        CharSequence summary = mContext.getText(R.string.pocket_mode_tip);
        preference.setSummary(summary);
    }
​
    @Override
    public int getAvailabilityStatus() {
        return SystemProperties.getBoolean("ro.config.wake_gesture", false) ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
    }
​
    @Override
    public void onStart() {
        if (mSettingObserver != null) {
            mSettingObserver.register(mContext.getContentResolver());
            mSettingObserver.onChange(false, null);
        }
    }
​
    @Override
    public void onStop() {
        if (mSettingObserver != null) {
            mSettingObserver.unregister(mContext.getContentResolver());
        }
    }
​
​
    private class SettingObserver extends ContentObserver {
        private final Uri mGestureUri = Settings.Secure.getUriFor(
                Settings.Secure.POCKET_MODE);
​
        private final Preference mPreference;
​
        SettingObserver(Preference preference) {
            super(new Handler());
            mPreference = preference;
        }
​
        public void register(ContentResolver cr) {
            cr.registerContentObserver(mGestureUri, false, this);
        }
​
        public void unregister(ContentResolver cr) {
            cr.unregisterContentObserver(this);
        }
​
        @Override
        public void onChange(boolean selfChange, Uri uri) {
            super.onChange(selfChange, uri);
            if (uri == null || mGestureUri.equals(uri)) {
                updateState(mPreference);
            }
        }
    }
​
    @Override
    public int getSliceHighlightMenuRes() {
        return 0;
    }
}

在getAvailabilityStatus()这个方法中,使用了宏控,可以根据实际需求自行选择开关的状态。各级菜单的定义以及其界面的实现,主要是对交互界面的实现,除数据库的存储外,不涉及到逻辑的处理。

二、获取距离传感器以及功能实现

添加模块:framework/base

目前智能亮屏方式有两种,抬腕亮屏和双击亮屏。口袋模式的实现方式则是针对这两种亮屏方式进行实现。当口袋模式打开的时候,pSensor如果检测到有物体靠近,就使抬腕亮屏和双击亮屏功能失效,否则,抬腕亮屏和双击亮屏功能正常实现。

设置数据库属性

路径: core/java/android/provider/Settings.java

        /**
         * @hide
         */
        public static final String POCKET_MODE =
                "pocket_mode";
​

获取距离的传感器ProximityCheck.java

路径:services/core/java/com/android/server/policy/ProximityCheck.java

package com.android.server.policy;
​
import android.view.KeyEvent;
import android.os.Handler;
import android.util.Slog;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.os.PowerManager;
import android.os.PowerManager.WakeReason;
import android.os.SystemClock;
​
public class ProximityCheck {
​
    private final SensorManager mSensorManager;
    private KeyEvent event;
    private boolean mRegistered;
    private final Handler mHandler;
    static final String TAG = "ProximityCheck";
    PowerManager mPowerManager;
​
    ProximityCheck(Context context, Handler handler) {
        mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
        mPowerManager= (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        mHandler = handler;
    }
​
    private final SensorEventListener mSensorEventListener = new SensorEventListener() {
        @Override
        public void onSensorChanged(SensorEvent event) {
            if (event.values.length == 0) {
                Slog.w(TAG, "ProximityCheck Event has no values!");
                finishWithResult(false);
            } else {
                boolean isNear = event.values[0] != 1.0f;
                Slog.d(TAG, "ProximityCheck isNear:" + isNear+" "+event.values[0]);
                finishWithResult(isNear);
            }
        }
​
        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
​
        }
    };
​
    private final Runnable mTimeoutRunnable = () -> {
        Slog.w(TAG, "ProximityCheck timeout!");
        finishWithResult(false);
    };
​
    public void onResult(boolean isNear) {
        Slog.w(TAG, "ProximityCheck onResult:"+isNear);
        if(isNear){
            mPowerManager.goToSleep(SystemClock.uptimeMillis());
        }
    }
​
    public void check() {
        Slog.d(TAG, "ProximityCheck check");
        mRegistered = true;
        mSensorManager.registerListener(mSensorEventListener,
                mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY), SensorManager.SENSOR_DELAY_NORMAL, mHandler);
        mHandler.postDelayed(mTimeoutRunnable, 500);
    }
​
    private void finishWithResult(boolean isNear) {
        onResult(isNear);
        if (mRegistered) {
            mRegistered = false;
            mHandler.removeCallbacks(mTimeoutRunnable);
            mSensorManager.unregisterListener(mSensorEventListener);
        }
    }
}

口袋模式功能的实现PhoneWindowManager.java

路径:services/core/java/com/android/server/policy/PhoneWindowManager.java

1、声明ProximityCheck。

private ProximityCheck proximityCheck;

2、抬腕唤醒时,检测是否有物体靠近

在抬腕亮屏的onWakeUp方法中创建ProximityCheck对象,并获取到口袋模式的开关是否打开,如果打开则是调用ProximityCheck对象中的check方法。

{
                if(proximityCheck == null ){
                    proximityCheck = new ProximityCheck(mContext, mHandler);
                }
                if (shouldEnableWakeGestureLp()) {
                    performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, false,
                            "Wake Up");
                    wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromWakeGesture,
                            PowerManager.WAKE_REASON_GESTURE, "android.policy:GESTURE");
                    boolean pocketMode = Settings.Secure.getInt(mContext.getContentResolver(),Settings.Secure.POCKET_MODE,0) != 0;
                    if(pocketMode) {
                        proximityCheck.check();
                    }
            }
        }
​

3、双击唤醒时,检测是否有物体靠近

在interceptKeyBeforeQueueing方法中上报各种keycode的下面添加一个双击亮屏的case KeyEvent.keycode,然后创建ProximityCheck对象,并获取到口袋模式的开关是否打开,如果打开则是调用ProximityCheck对象中的check方法。

case KeyEvent.KEYCODE_U:
                if(proximityCheck == null ){
                    proximityCheck = new ProximityCheck(mContext, mHandler);
                }
                if(down){
                    boolean pocketMode = Settings.Secure.getInt(mContext.getContentResolver(),Settings.Secure.POCKET_MODE,0) != 0;
                    mPowerManager.wakeUp(event.getEventTime(), PowerManager.WAKE_REASON_WAKE_KEY, "android:policy:double_click");
                    if(pocketMode){
                        proximityCheck.check();
                    }
                }
                break;
  • 12
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值