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

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

如何修改Android设备添加重启、飞行模式、静音模式等功能(二)_第1张图片" src="https://img.it610.com/image/product/1f6d0b0441d345e48a49950edf22b6b9.png" width="650" height="330" style="border:1px solid black;">

如何修改Android设备添加重启、飞行模式、静音模式等功能(二)_第2张图片" src="https://img.it610.com/image/product/a9396ec5974f4ec0b2eb2ad9b9640da1.png" width="645" height="383" style="border:1px solid black;">


 /**     * 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() {                    //rebootmWindowManagerFuncs.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中 如何修改Android设备添加重启、飞行模式、静音模式等功能(二)_第3张图片" src="https://img.it610.com/image/product/faf06fd5655c466b8812239a0385d459.png" width="650" height="495" style="border:1px solid black;">
 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 ouyangpublic void reboot(boolean confirm);    }
添加reboot方法。 但这只是添加接口而已,它的具体实现在呢?找了许久在 frameworks\base\services\java\com\android\server\wm\windowManagerService.java中找到了这个接口的实现。

如何修改Android设备添加重启、飞行模式、静音模式等功能(二)_第4张图片" src="https://img.it610.com/image/product/9d7d4d3409c54658b3c88ae17bceb142.png" width="606" height="246" style="border:1px solid black;"> 在该类中加入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中,
如何修改Android设备添加重启、飞行模式、静音模式等功能(二)_第5张图片" src="https://img.it610.com/image/product/64c28ae488584a8ab622dafbd02534ad.png" width="650" height="355" style="border:1px solid black;">
 /**     * 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方法

如何修改Android设备添加重启、飞行模式、静音模式等功能(二)_第6张图片" src="https://img.it610.com/image/product/b86d8ff75bfe4d1e9b60dfb262c5466b.png" width="650" height="367" style="border:1px solid black;">
如何修改Android设备添加重启、飞行模式、静音模式等功能(二)_第7张图片" src="https://img.it610.com/image/product/19914872962645428513b1b9c358454f.png" width="650" height="350" style="border:1px solid black;">
 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 startedfinal 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 codefinal 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 如何修改Android设备添加重启、飞行模式、静音模式等功能(二)_第8张图片" src="https://img.it610.com/image/product/5b185b85831d486294eb6f95d8915188.jpg" width="621" height="215" style="border:1px solid black;">
 <!--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" />  
如何修改Android设备添加重启、飞行模式、静音模式等功能(二)_第9张图片" src="https://img.it610.com/image/product/e54bdc10537143528c39425768d4b9a5.jpg" width="623" height="138" style="border:1px solid black;"> 最后还得确认 framework/base/core/res/res/values/config.xml文件中的config_longPressOnPowerBehavior属性变成1



最后重新编译即可



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

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

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

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


更多相关文章

  1. IPC机制: Android中的IPC简介和多进程模式
  2. Delphi XE8 iOS与Android移动应用开发(APP开发)[完整中文版]
  3. Android之父安迪·鲁宾
  4. 【Android(安卓)编程架构】MVC/MVP/MVVM
  5. 在Ubuntu中和Android中添加开机自启动的守护进程
  6. 【Android】ViewPager实现图片左右滑动播放及添加点击事件
  7. Ubuntu Linux下android源码下载方法
  8. Android(安卓)DiskLruCache完全解析,硬盘缓存的最佳方案
  9. 第二章 Android动态加载、热更新、热修复、插件化系列文章 之 认

随机推荐

  1. Android(安卓)内存优化
  2. Head Fisrt Android(安卓)Development读
  3. LocationManager定位
  4. 回收图片
  5. android 常用权限备份
  6. Caching Bitmaps
  7. hcidump用法
  8. Android(安卓)TV -1.1- Get Started with
  9. android百度地图
  10. androidstudio加载项目问题