Android系统移植与调试之------->如何修改Android设备添加重启、飞行模式、静音模式等功能(二)

简介: 今天要说的是为Android设备添加重启、飞行模式、静音模式按钮,客户需求中需要添加这项功能,在长按电源键弹出的菜单中没有这些选项,谨以此文记录自己添加这个功能的过程。

今天要说的是为Android设备添加重启、飞行模式、静音模式按钮,客户需求中需要添加这项功能,在长按电源键弹出的菜单中没有这些选项,谨以此文记录自己添加这个功能的过程。

首先找到长按电源键弹出的对话框,在frameworks\base\policy\src\com\android\internal\policy\impl\GlobalActions.java文件中,修改createDialog()方法。



 /**
     * Create the global actions dialog.
     * @return A new dialog.
     */
    private AlertDialog createDialog() {
        // Simple toggle style if there's no vibrator, otherwise use a tri-state
        if (!mHasVibrator) {
            mSilentModeAction = new SilentModeToggleAction();
        } else {
            mSilentModeAction = new SilentModeTriStateAction(mContext, mAudioManager, mHandler);
        }
        mAirplaneModeOn = new ToggleAction(
                R.drawable.ic_lock_airplane_mode,
                R.drawable.ic_lock_airplane_mode_off,
                R.string.global_actions_toggle_airplane_mode,
                R.string.global_actions_airplane_mode_on_status,
                R.string.global_actions_airplane_mode_off_status) {

            void onToggle(boolean on) {
                if (mHasTelephony && Boolean.parseBoolean(
                        SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) {
                    mIsWaitingForEcmExit = true;
                    // Launch ECM exit dialog
                    Intent ecmDialogIntent =
                            new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null);
                    ecmDialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    mContext.startActivity(ecmDialogIntent);
                } else {
                    changeAirplaneModeSystemSetting(on);
                }
            }

            @Override
            protected void changeStateFromPress(boolean buttonOn) {
                if (!mHasTelephony) return;

                // In ECM mode airplane state cannot be changed
                if (!(Boolean.parseBoolean(
                        SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE)))) {
                    mState = buttonOn ? State.TurningOn : State.TurningOff;
                    mAirplaneState = mState;
                }
            }

            public boolean showDuringKeyguard() {
                return true;
            }

            public boolean showBeforeProvisioning() {
                return false;
            }
        };
        onAirplaneModeChanged();

        mItems = new ArrayList<Action>();

        // first: power off
        mItems.add(
            new SinglePressAction(
                    com.android.internal.R.drawable.ic_lock_power_off,
                    R.string.global_action_power_off) {

                public void onPress() {
                    // shutdown by making sure radio and power are handled accordingly.
                    mWindowManagerFuncs.shutdown();
                }

                public boolean onLongPress() {
                    mWindowManagerFuncs.rebootSafeMode();
                    return true;
                }

                public boolean showDuringKeyguard() {
                    return true;
                }

                public boolean showBeforeProvisioning() {
                    return true;
                }
            });

	//edited by ouyang started
	// next: reboot
        mItems.add(
            new SinglePressAction(
                    com.android.internal.R.drawable.ic_lock_power_off,
                    R.string.global_action_reboot) {

                public void onPress() {
                    	//reboot
			mWindowManagerFuncs.reboot(true);
                }

                public boolean onLongPress() {
                    mWindowManagerFuncs.rebootSafeMode();
                    return true;
                }

                public boolean showDuringKeyguard() {
                    return true;
                }

                public boolean showBeforeProvisioning() {
                    return true;
                }
            });
	//edited by ouyang ended


        // next: airplane mode
       	 mItems.add(mAirplaneModeOn);

        // last: silent mode
        if (SHOW_SILENT_TOGGLE) {
            mItems.add(mSilentModeAction);
        }

	//edited by ouyang ended
        List<UserInfo> users = mContext.getPackageManager().getUsers();
        if (users.size() > 1) {
            UserInfo currentUser;
            try {
                currentUser = ActivityManagerNative.getDefault().getCurrentUser();
            } catch (RemoteException re) {
                currentUser = null;
            }
            for (final UserInfo user : users) {
                boolean isCurrentUser = currentUser == null
                        ? user.id == 0 : (currentUser.id == user.id);
                SinglePressAction switchToUser = new SinglePressAction(
                        com.android.internal.R.drawable.ic_menu_cc,
                        (user.name != null ? user.name : "Primary")
                        + (isCurrentUser ? " \u2714" : "")) {
                    public void onPress() {
                        try {
                            ActivityManagerNative.getDefault().switchUser(user.id);
                            getWindowManager().lockNow();
                        } catch (RemoteException re) {
                            Log.e(TAG, "Couldn't switch user " + re);
                        }
                    }

                    public boolean showDuringKeyguard() {
                        return true;
                    }

                    public boolean showBeforeProvisioning() {
                        return false;
                    }
                };
                mItems.add(switchToUser);
            }
        }

        mAdapter = new MyAdapter();

        final AlertDialog.Builder ab = new AlertDialog.Builder(mContext);

        ab.setAdapter(mAdapter, this)
                .setInverseBackgroundForced(true);

        final AlertDialog dialog = ab.create();
        dialog.getListView().setItemsCanFocus(true);
        dialog.getListView().setLongClickable(true);
        dialog.getListView().setOnItemLongClickListener(
                new AdapterView.OnItemLongClickListener() {
                    @Override
                    public boolean onItemLongClick(AdapterView<?> parent, View view, int position,
                            long id) {
                        return mAdapter.getItem(position).onLongPress();
                    }
        });
        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);

        dialog.setOnDismissListener(this);

        return dialog;
    }

在GlobalActionsDialog方法可以看 mItems.add这个方法是添加菜单选项的,该菜单的添加的第一个选项就是关机选项。可以仿照关机的Item添加一个重启的选项,如上面的代码所示;这样就解决了在长按的电源键弹出的对话框中添加一个重启选项了。当然这仅仅是添加一个显示而已,接下来就为这个选项添加逻辑控制代码了。

在上面的代码中使用的mWindowManagerFuncs.reboot方法和R.string.global_action_reboot资源(资源的添加放到最后说),默认是不存在的,所以需要在自己手动添加。

2、 首先在找到WindowManagerFuncs这个所在的位置,在frameworks\base\core\java\android\view\WindowManagerPolicy.java中
 public interface WindowManagerFuncs {
        public static final int LID_ABSENT = -1;
        public static final int LID_CLOSED = 0;
        public static final int LID_OPEN = 1;

        /**
         * Ask the window manager to re-evaluate the system UI flags.
         */
        public void reevaluateStatusBarVisibility();

        /**
         * Add a fake window to the window manager.  This window sits
         * at the top of the other windows and consumes events.
         */
        public FakeWindow addFakeWindow(Looper looper,
                InputEventReceiver.Factory inputEventReceiverFactory,
                String name, int windowType, int layoutParamsFlags, boolean canReceiveKeys,
                boolean hasFocus, boolean touchFullscreen);

        /**
         * Returns a code that describes the current state of the lid switch.
         */
        public int getLidState();

        /**
         * Creates an input channel that will receive all input from the input dispatcher.
         */
        public InputChannel monitorInput(String name);

        /**
         * Switch the keyboard layout for the given device.
         * Direction should be +1 or -1 to go to the next or previous keyboard layout.
         */
        public void switchKeyboardLayout(int deviceId, int direction);

        public void shutdown();
        public void rebootSafeMode();
	//edited by ouyang
	public void reboot(boolean confirm);
    }
添加reboot方法。 但这只是添加接口而已,它的具体实现在呢?找了许久在 frameworks\base\services\java\com\android\server\wm\windowManagerService.java中找到了这个接口的实现。

在该类中加入reboot()方法,该方法调用ShutdownThread的reboot方法
  // Called by window manager policy.  Not exposed externally.
    @Override
    public void shutdown() {
        ShutdownThread.shutdown(mContext, true);
    }
    //edited by ouyang start	
    public void reboot(boolean confirm){
	ShutdownThread.reboot(mContext,null,confirm);	
    }
    //edited by ouyang end	

同样在仿照关机的原理添加reboot的具体实现代码,既然在ShutdownThread这个类中提供了shutdown和rebootSafeMode的方法,那按理也应该有reboot的方法,或者类似reboot的方法。找到Shutdown.java文件,在frameworks\base\services\java\com\android\server\power\ShutdownThread.java中,


 /**
     * Request a clean shutdown, waiting for subsystems to clean up their
     * state etc.  Must be called from a Looper thread in which its UI
     * is shown.
     *
     * @param context Context used to display the shutdown progress dialog.
     * @param reason code to pass to the kernel (e.g. "recovery"), or null.
     * @param confirm true if user confirmation is needed before shutting down.
     */
    public static void reboot(final Context context, String reason, boolean confirm) {
        mReboot = true;
        mRebootSafeMode = false;
        mRebootReason = reason;
        shutdownInner(context, confirm);
    }


其中提供了一个静态的reboot方法,所以在windowManagerService.java中的reboot实现中直接调用ShutdownThread中reboot即可。
 public static void reboot(final Context context, String reason, boolean confirm);有三个参数,后两个参数解释如下: reason  如果值为是null,正常重启;如果是recovery,系统重启进入recovery mode ;confirm为true显示关机提示框,需要用户【确认】;false不显示提示框,直接关机。

到此重启功能基本上可以使用了(除资源还没有添加之外),但是此时选择重启选项时,其提示还是不够关机的提示,所以还要修改选择“重启”时的对话框的提示。
在frameworks\base\services\java\com\android\server\pm\ShutdownThread.java中

修改shutdownInner方法



 static void shutdownInner(final Context context, boolean confirm) {
        // ensure that only one thread is trying to power down.
        // any additional calls are just returned
        synchronized (sIsStartedGuard) {
            if (sIsStarted) {
                Log.d(TAG, "Request to shutdown already running, returning.");
                return;
            }
        }

        final int longPressBehavior = context.getResources().getInteger(
                        com.android.internal.R.integer.config_longPressOnPowerBehavior);
	//edited by ouyang started
	final int resourceId =mReboot
	?com.android.internal.R.string.reboot_confirm
	:(mRebootSafeMode
                ? com.android.internal.R.string.reboot_safemode_confirm
                : (longPressBehavior == 2
                        ? com.android.internal.R.string.shutdown_confirm_question
                        : com.android.internal.R.string.shutdown_confirm)); 
	//edited by ouyang ended  
     
        /**
	//resource code
	final int resourceId = mRebootSafeMode
                ? com.android.internal.R.string.reboot_safemode_confirm
                : (longPressBehavior == 2
                        ? com.android.internal.R.string.shutdown_confirm_question
                        : com.android.internal.R.string.shutdown_confirm);
	*/
        Log.d(TAG, "Notifying thread to start shutdown longPressBehavior=" + longPressBehavior);

        if (confirm) {
            final CloseDialogReceiver closer = new CloseDialogReceiver(context);
            final AlertDialog dialog = new AlertDialog.Builder(context)
		    /* 	
		    //source code
                    .setTitle(mRebootSafeMode
                            ? com.android.internal.R.string.reboot_safemode_title
                            : com.android.internal.R.string.power_off)
                    .setMessage(resourceId)
		    */
		    //edited by ouyang started
                    .setTitle(mReboot
                        ?com.android.internal.R.string.global_action_reboot
                        :(mRebootSafeMode
                            ? com.android.internal.R.string.reboot_safemode_title
                            : com.android.internal.R.string.power_off))
                    .setMessage(resourceId)
                    //edited by ouyang ended	
	
                    .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {
                            beginShutdownSequence(context);
                        }
                    })
                    .setNegativeButton(com.android.internal.R.string.no, null)
                    .create();
            closer.dialog = dialog;
            dialog.setOnDismissListener(closer);
            dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
            dialog.show();
        } else {
            beginShutdownSequence(context);
        }
    }

至此关于代码部分的改动全部完成,接下就添加需要添加使用到的资源了,就是其中使用的字符串,为了简单起见就添加了英文和简体中文:
在对应的资源文件中添加:
frameworks\base\core\res\res\values\strings.xml

 <!--edited by ouyang started-->
    <string name="global_action_reboot">Reboot</string>
    <string name="reboot_confirm">Do you want to reboot your device?</string>	
    <!--edited by ouyang started-->
frameworks\base\core\res\res\values-zh-rCN\ strings.xml
<!--edited by ouyang started-->
    <string name="global_action_reboot">重启</string>
    <string name="reboot_confirm">您要重新启动您的设备吗?</string>           
    <!--edited by ouyang started-->

现在已经添加了好这些资源,但是现在还不能使用,此时编译会出现找不到该资源的错误,还需要在 frameworks\base\core\res\res\values\public.xml 文件中进行资源声明:
<java-symbol type="string" name="global_action_reboot" />  
<java-symbol type="string" name="reboot_confirm" />  
最后还得确认 framework/base/core/res/res/values/config.xml文件中的config_longPressOnPowerBehavior属性变成1




最后重新编译即可



==================================================================================================

  作者:欧阳鹏  欢迎转载,与人分享是进步的源泉!

  转载请保留原文地址http://blog.csdn.net/ouyang_peng

==================================================================================================


相关文章
|
1月前
|
Android开发
Android开发表情emoji功能开发
本文介绍了一种在Android应用中实现emoji表情功能的方法,通过将图片与表情字符对应,实现在`TextView`中的正常显示。示例代码展示了如何使用自定义适配器加载emoji表情,并在编辑框中输入或删除表情。项目包含完整的源码结构,可作为开发参考。视频演示和源码详情见文章内链接。
64 4
Android开发表情emoji功能开发
|
16天前
|
安全 Android开发 iOS开发
Android vs iOS:探索移动操作系统的设计与功能差异###
【10月更文挑战第20天】 本文深入分析了Android和iOS两个主流移动操作系统在设计哲学、用户体验、技术架构等方面的显著差异。通过对比,揭示了这两种系统各自的独特优势与局限性,并探讨了它们如何塑造了我们的数字生活方式。无论你是开发者还是普通用户,理解这些差异都有助于更好地选择和使用你的移动设备。 ###
32 3
|
2月前
|
Android开发 开发者
Android平台无纸化同屏如何实现实时录像功能
Android平台无纸化同屏,如果需要本地录像的话,实现难度不大,只要复用之前开发的录像模块的就可以,对我们来说,同屏采集这块,只是数据源不同而已,如果是自采集的其他数据,我们一样可以编码录像。
|
3月前
|
Android开发
基于Amlogic 安卓9.0, 驱动简说(四):Platform平台驱动,驱动与设备的分离
本文介绍了如何在基于Amlogic T972的Android 9.0系统上使用Platform平台驱动框架和设备树(DTS),实现设备与驱动的分离,并通过静态枚举在设备树中描述设备,自动触发驱动程序的加载和设备创建。
48 0
基于Amlogic 安卓9.0, 驱动简说(四):Platform平台驱动,驱动与设备的分离
|
3月前
|
Android开发 C语言
基于Amlogic 安卓9.0, 驱动简说(二):字符设备驱动,自动创建设备
这篇文章是关于如何在基于Amlogic T972的Android 9.0系统上,通过自动分配设备号和自动创建设备节点文件的方式,开发字符设备驱动程序的教程。
53 0
基于Amlogic 安卓9.0, 驱动简说(二):字符设备驱动,自动创建设备
|
3月前
|
自然语言处理 Shell Linux
基于Amlogic 安卓9.0, 驱动简说(一):字符设备驱动,手动创建设备
本文是关于在Amlogic安卓9.0平台上创建字符设备驱动的教程,详细介绍了驱动程序的编写、编译、部署和测试过程,并提供了完整的源码和应用层调用示例。
73 0
基于Amlogic 安卓9.0, 驱动简说(一):字符设备驱动,手动创建设备
|
3月前
|
传感器 Android开发 芯片
不写一行代码(三):实现安卓基于i2c bus的Slaver设备驱动
本文是系列文章的第三篇,展示了如何在Android系统中利用现有的i2c bus驱动,通过编写设备树节点和应用层的控制代码,实现对基于i2c bus的Slaver设备(如六轴陀螺仪模块QMI8658C)的控制,而无需编写设备驱动代码。
44 0
不写一行代码(三):实现安卓基于i2c bus的Slaver设备驱动
|
Java 调度 Android开发
android体系课-系统启动流程-之zygote进程启动过程源码分析
笔者刚开始学习Android的时候也和大部分同学一样,只会使用一些应用层面的知识,对于一些比较常见的开源框架如<mark>RxJava</mark>,<mark>OkHttp</mark>,<mark>Retrofit</mark>,以及后来谷歌推出的<mark>协程</mark>等,都只在使用层面,对于他们<mark>内部原理</mark>,基本没有去了解觉得够用就可以了,又比如Activity,Service等四大组件的使用原理,系统开机过程,Launcher启动过程等知之甚少,知其然而不知其所以然,结果就是出现某些问题,不知道从哪里找原因,只能依赖万能的百度,但是百度看多了,你会发现自己
|
Java 调度 Android开发
android体系课-系统启动流程-之SystemServer启动过程源码分析
笔者刚开始学习Android的时候也和大部分同学一样,只会使用一些应用层面的知识,对于一些比较常见的开源框架如<mark>RxJava</mark>,<mark>OkHttp</mark>,<mark>Retrofit</mark>,以及后来谷歌推出的<mark>协程</mark>等,都只在使用层面,对于他们<mark>内部原理</mark>,基本没有去了解觉得够用就可以了,又比如Activity,Service等四大组件的使用原理,系统开机过程,Launcher启动过程等知之甚少,知其然而不知其所以然,结果就是出现某些问题,不知道从哪里找原因,只能依赖万能的百度,但是百度看多了,你会发现自己
下一篇
无影云桌面