android M Power Button three times Make Emergency Call

android M Power Button three times Make Emergency Call

Public utility and Emergency Services - Mobile handsets shall have an SOS alert button. The SOS alert button shall be implemented as per Government of India regulatory requirement:

  • There shall be a dedicated configuring digit “9” in the dialler. On long press of this digit, device shall initiate emergency service number “112”
  • On pressing the Power Button three times, device shall initiate emergency service number “112”.

这是印度政府为了女性权益的保障性政策吗?额,也许是我想多了,不过想到印度就想到了。。。。。。下面进入正题,哈哈


先来说说长按9键拨打紧急号码的实现:

在android/packages/apps/Dialer 的DialpadFragment.onLongClick里面进行处理:这里很简单,直接调用系统提供的方法就可以了,DialerUtils.startActivityWithErrorToast其实最终还是调用了6.0新提供的接口TelecomManager.placeCall

            case R.id.nine: {
                if (mDigits.length() == 1) {
                    if (R.id.nine == id) {
                         final DialtactsActivity activity = getActivity() instanceof DialtactsActivity
                                      ? (DialtactsActivity) getActivity() : null;
                         final Intent intent =
                                   IntentUtil.getCallIntent("112", activity != null
                                          ? activity.getCallOrigin()
                                                  : null);
                        DialerUtils.startActivityWithErrorToast(getActivity(), intent);
                        hideAndClearDialpad(false);
                        return true;
                    }

再来说说连续点击三次power建拨打紧急号码的实现:

1.因为是点击power键后的处理,所以我们应该在android/frameworks/base/services PhoneWindowManager.java里面去截获按键的点击事件,在interceptPowerKeyDown里我们看到了GestureLauncherService

GestureLauncherService gestureService = LocalServices.getService(
                GestureLauncherService.class);
        boolean gesturedServiceIntercepted = false;
         if (gestureService != null) {
 -            gesturedServiceIntercepted = gestureService.interceptPowerKeyDown(event, interactive);
+            //On pressing the Power Button three times,device shall initiate emergency service number“112”.
+            gesturedServiceIntercepted = gestureService.interceptPowerKeyDown(event, interactive, mHandler);
         }

跳到GestureLauncherService. interceptPowerKeyDown方法中去看看

-    public boolean interceptPowerKeyDown(KeyEvent event, boolean interactive) {
-        boolean launched = false;
+    //[Feature]On pressing the Power Button three times,device shall initiate emergency service number“112”.
+    public boolean interceptPowerKeyDown(KeyEvent event, boolean interactive, Handler handler) {
         boolean intercept = false;
+        boolean launched = false;
         long doubleTapInterval;
         synchronized (this) {
             doubleTapInterval = event.getEventTime() - mLastPowerDown;
-            if (mCameraDoubleTapPowerEnabled
-                    && doubleTapInterval < CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS
+            if (doubleTapInterval < CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS
                     && doubleTapInterval > CAMERA_POWER_DOUBLE_TAP_MIN_TIME_MS) {
-                launched = true;
-                intercept = interactive;
+                mAccount++;
+                if(mCameraDoubleTapPowerEnabled){
+                    launched = true;
+                    intercept = interactive;
+                }
+                if (mAccount == 3) {
+                    Log.d(TAG, "tap three times");
+                    handler.removeCallbacks(mCameraLaunchRunnable);
+                    interceptEmergencyCall();
+                    mAccount = 1;
+                } else if (launched) {
+                    Log.d(TAG, "Tap two times camera launched " + launched);
+                    handler.postDelayed(mCameraLaunchRunnable, 450L);
+                }else if (!launched){
+                    Log.d(TAG, "Tap two times but not launch camera");
+                    handler.postDelayed(mTriplePressDelay, 450L);
+                }
             }
             mLastPowerDown = event.getEventTime();
         }
-        if (launched) {
-            Slog.i(TAG, "Power button double tap gesture detected, launching camera. Interval="
-                    + doubleTapInterval + "ms");
-            launched = handleCameraLaunchGesture(false /* useWakelock */,
+        mCopydoubleTapInterval = doubleTapInterval ;
+        MetricsLogger.histogram(mContext, "power_double_tap_interval", (int) doubleTapInterval);
+        return intercept && launched;
+    }

这里我们看到系统给我们提供了一个判断连续点击两次power键启动系统camera的例子,然而我们要做的feature是判断连续点击三次拨打紧急号码,好,那我们就在这个方法的基础之上实现我们的需求。

+    private final Runnable mCameraLaunchRunnable = new Runnable() {
+        @Override
+        public void run() {
+            mAccount = 1;
+            boolean mHasLaunched = true;
+            mHasLaunched = handleCameraLaunchGesture(false /* useWakelock */,
                     StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP);
-            if (launched) {
+            if (mHasLaunched) {
                 MetricsLogger.action(mContext, MetricsLogger.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE,
-                        (int) doubleTapInterval);
+                        (int) mCopydoubleTapInterval);
             }
         }
-        MetricsLogger.histogram(mContext, "power_double_tap_interval", (int) doubleTapInterval);
-        return intercept && launched;
+    };
+
+    private final Runnable mTriplePressDelay = new Runnable() {
+        @Override
+        public void run() {
+            mAccount = 1;
+        }
+    };
+
+    private void interceptEmergencyCall() {
+        Intent intent = new Intent();
+        intent.setAction(EMERGENCY_CALL);
+        mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
     }
+    //@end 

这里我写了两个Runnable,mCameraLaunchRunnable 是执行原本启动camera的代码,并做延时处理,mTriplePressDelay 因为用户可以通过设置 enable和disenable power两次启动camera这个功能,通过mCameraDoubleTapPowerEnabled这个值来判断,所以我加了个mTriplePressDelay 的延时来处理当用户disenable 启动camera的功能,最后通过interceptEmergencyCall方法发个广播出去。当然还需要一些变量的定义如下:

+    /**
+     * On pressing the Power Button three times, device shall initiate emergency service number 112
+     */
+    private int mAccount = 1;
+    private long mCopydoubleTapInterval;
+    private static final String EMERGENCY_CALL = "android.intent.action.ACTION_SEND_EMERGENCY_CALL";

2.广播发出去了我们需要个接受者,来处理拨打紧急号码这个动作,当手机处于锁屏界面的时候,我们可以点击界面上的紧急号码按钮直接拨打紧急号码,这里我们就在处理锁屏界面的紧急号码里面呼出我们的紧急号码,在android/packages/services/Telephony下面我们新建一个EmergencyCallReceiver.java,用于接收广播并拨打号码,因为是静态注册所以需要在AndroidManifest.xml声明一下

+package com.android.phone;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.telecom.PhoneAccount;
+import android.util.Log;
+
+/**
+ * On pressing the Power Button three times, device shall initiate emergency service number“112”
+ */
+public class EmergencyCallReceiver extends BroadcastReceiver {
+    private static final String TAG = "EmergencyCallReceiver";
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        Log.d(TAG,"EmergencyCall_Receive_Success ");
+        String mEmergencyNumber = "112";
+        Intent mintent = new Intent(Intent.ACTION_CALL_EMERGENCY);
+        mintent.setData(Uri.fromParts(PhoneAccount.SCHEME_TEL, mEmergencyNumber, null));
+        mintent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        context.startActivity(mintent);
+    }
+}
+        <!--[Feature]On pressing the Power Button three times,device shall initiate emergency service number“112”.-->
+        <receiver android:name=".EmergencyCallReceiver">
+            <intent-filter>
+                <action android:name="android.intent.action.ACTION_SEND_EMERGENCY_CALL"/>
+            </intent-filter>
+        </receiver>
总结:
  • 为什么要用两个Runnable来做延时处理?
    因为我们和系统的两次power启动相机的快捷方式有点儿冲突,当我们连续点击了两次power键时系统就应该启动相机了,再点击一次去打电话但是相机已经启动了,所以就采用了一个延时操作,在450毫秒之内有没有下次power事件操作,有的话就remove准备做的操作。
  • 为什么要发送广播让另外一个模块去拨打电话?
    因为我们没有权限,而且在PhoneWindowManager里面我也不知道怎么添加权限进去,所以,索性就让有权限的人去做事情。
    /**
     * Places a new outgoing call to the provided address using the system telecom service with
     * the specified extras.
     *
     * This method is equivalent to placing an outgoing call using {@link Intent#ACTION_CALL},
     * except that the outgoing call will always be sent via the system telecom service. If
     * method-caller is either the user selected default dialer app or preloaded system dialer
     * app, then emergency calls will also be allowed.
     *
     * Requires permission: {@link android.Manifest.permission#CALL_PHONE}
     *
     * Usage example:
     * <pre>
     * Uri uri = Uri.fromParts("tel", "12345", null);
     * Bundle extras = new Bundle();
     * extras.putBoolean(TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, true);
     * telecomManager.placeCall(uri, extras);
     * </pre>
     *
     * The following keys are supported in the supplied extras.
     * <ul>
     *   <li>{@link #EXTRA_OUTGOING_CALL_EXTRAS}</li>
     *   <li>{@link #EXTRA_PHONE_ACCOUNT_HANDLE}</li>
     *   <li>{@link #EXTRA_START_CALL_WITH_SPEAKERPHONE}</li>
     *   <li>{@link #EXTRA_START_CALL_WITH_VIDEO_STATE}</li>
     * </ul>
     *
     * @param address The address to make the call to.
     * @param extras Bundle of extras to use with the call.
     */
    public void placeCall(Uri address, Bundle extras) {
        ITelecomService service = getTelecomService();
        if (service != null) {
            if (address == null) {
                Log.w(TAG, "Cannot place call to empty address.");
            }
            try {
                service.placeCall(address, extras == null ? new Bundle() : extras,
                        mContext.getOpPackageName());
            } catch (RemoteException e) {
                Log.e(TAG, "Error calling ITelecomService#placeCall", e);
            }
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值