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

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



[java]  view plain copy
  1. /** 
  2.     * Create the global actions dialog. 
  3.     * @return A new dialog. 
  4.     */  
  5.    private AlertDialog createDialog() {  
  6.        // Simple toggle style if there's no vibrator, otherwise use a tri-state  
  7.        if (!mHasVibrator) {  
  8.            mSilentModeAction = new SilentModeToggleAction();  
  9.        } else {  
  10.            mSilentModeAction = new SilentModeTriStateAction(mContext, mAudioManager, mHandler);  
  11.        }  
  12.        mAirplaneModeOn = new ToggleAction(  
  13.                R.drawable.ic_lock_airplane_mode,  
  14.                R.drawable.ic_lock_airplane_mode_off,  
  15.                R.string.global_actions_toggle_airplane_mode,  
  16.                R.string.global_actions_airplane_mode_on_status,  
  17.                R.string.global_actions_airplane_mode_off_status) {  
  18.   
  19.            void onToggle(boolean on) {  
  20.                if (mHasTelephony && Boolean.parseBoolean(  
  21.                        SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) {  
  22.                    mIsWaitingForEcmExit = true;  
  23.                    // Launch ECM exit dialog  
  24.                    Intent ecmDialogIntent =  
  25.                            new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null);  
  26.                    ecmDialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
  27.                    mContext.startActivity(ecmDialogIntent);  
  28.                } else {  
  29.                    changeAirplaneModeSystemSetting(on);  
  30.                }  
  31.            }  
  32.   
  33.            @Override  
  34.            protected void changeStateFromPress(boolean buttonOn) {  
  35.                if (!mHasTelephony) return;  
  36.   
  37.                // In ECM mode airplane state cannot be changed  
  38.                if (!(Boolean.parseBoolean(  
  39.                        SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE)))) {  
  40.                    mState = buttonOn ? State.TurningOn : State.TurningOff;  
  41.                    mAirplaneState = mState;  
  42.                }  
  43.            }  
  44.   
  45.            public boolean showDuringKeyguard() {  
  46.                return true;  
  47.            }  
  48.   
  49.            public boolean showBeforeProvisioning() {  
  50.                return false;  
  51.            }  
  52.        };  
  53.        onAirplaneModeChanged();  
  54.   
  55.        mItems = new ArrayList();  
  56.   
  57.        // first: power off  
  58.        mItems.add(  
  59.            new SinglePressAction(  
  60.                    com.android.internal.R.drawable.ic_lock_power_off,  
  61.                    R.string.global_action_power_off) {  
  62.   
  63.                public void onPress() {  
  64.                    // shutdown by making sure radio and power are handled accordingly.  
  65.                    mWindowManagerFuncs.shutdown();  
  66.                }  
  67.   
  68.                public boolean onLongPress() {  
  69.                    mWindowManagerFuncs.rebootSafeMode();  
  70.                    return true;  
  71.                }  
  72.   
  73.                public boolean showDuringKeyguard() {  
  74.                    return true;  
  75.                }  
  76.   
  77.                public boolean showBeforeProvisioning() {  
  78.                    return true;  
  79.                }  
  80.            });  
  81.   
  82. //edited by ouyang started  
  83. // next: reboot  
  84.        mItems.add(  
  85.            new SinglePressAction(  
  86.                    com.android.internal.R.drawable.ic_lock_power_off,  
  87.                    R.string.global_action_reboot) {  
  88.   
  89.                public void onPress() {  
  90.                     //reboot  
  91.         mWindowManagerFuncs.reboot(true);  
  92.                }  
  93.   
  94.                public boolean onLongPress() {  
  95.                    mWindowManagerFuncs.rebootSafeMode();  
  96.                    return true;  
  97.                }  
  98.   
  99.                public boolean showDuringKeyguard() {  
  100.                    return true;  
  101.                }  
  102.   
  103.                public boolean showBeforeProvisioning() {  
  104.                    return true;  
  105.                }  
  106.            });  
  107. //edited by ouyang ended  
  108.   
  109.   
  110.        // next: airplane mode  
  111.          mItems.add(mAirplaneModeOn);  
  112.   
  113.        // last: silent mode  
  114.        if (SHOW_SILENT_TOGGLE) {  
  115.            mItems.add(mSilentModeAction);  
  116.        }  
  117.   
  118. //edited by ouyang ended  
  119.        List users = mContext.getPackageManager().getUsers();  
  120.        if (users.size() > 1) {  
  121.            UserInfo currentUser;  
  122.            try {  
  123.                currentUser = ActivityManagerNative.getDefault().getCurrentUser();  
  124.            } catch (RemoteException re) {  
  125.                currentUser = null;  
  126.            }  
  127.            for (final UserInfo user : users) {  
  128.                boolean isCurrentUser = currentUser == null  
  129.                        ? user.id == 0 : (currentUser.id == user.id);  
  130.                SinglePressAction switchToUser = new SinglePressAction(  
  131.                        com.android.internal.R.drawable.ic_menu_cc,  
  132.                        (user.name != null ? user.name : "Primary")  
  133.                        + (isCurrentUser ? " \u2714" : "")) {  
  134.                    public void onPress() {  
  135.                        try {  
  136.                            ActivityManagerNative.getDefault().switchUser(user.id);  
  137.                            getWindowManager().lockNow();  
  138.                        } catch (RemoteException re) {  
  139.                            Log.e(TAG, "Couldn't switch user " + re);  
  140.                        }  
  141.                    }  
  142.   
  143.                    public boolean showDuringKeyguard() {  
  144.                        return true;  
  145.                    }  
  146.   
  147.                    public boolean showBeforeProvisioning() {  
  148.                        return false;  
  149.                    }  
  150.                };  
  151.                mItems.add(switchToUser);  
  152.            }  
  153.        }  
  154.   
  155.        mAdapter = new MyAdapter();  
  156.   
  157.        final AlertDialog.Builder ab = new AlertDialog.Builder(mContext);  
  158.   
  159.        ab.setAdapter(mAdapter, this)  
  160.                .setInverseBackgroundForced(true);  
  161.   
  162.        final AlertDialog dialog = ab.create();  
  163.        dialog.getListView().setItemsCanFocus(true);  
  164.        dialog.getListView().setLongClickable(true);  
  165.        dialog.getListView().setOnItemLongClickListener(  
  166.                new AdapterView.OnItemLongClickListener() {  
  167.                    @Override  
  168.                    public boolean onItemLongClick(AdapterView<?> parent, View view, int position,  
  169.                            long id) {  
  170.                        return mAdapter.getItem(position).onLongPress();  
  171.                    }  
  172.        });  
  173.        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);  
  174.   
  175.        dialog.setOnDismissListener(this);  
  176.   
  177.        return dialog;  
  178.    }  

在GlobalActionsDialog方法可以看 mItems.add这个方法是添加菜单选项的,该菜单的添加的第一个选项就是关机选项。可以仿照关机的Item添加一个重启的选项,如上面的代码所示;这样就解决了在长按的电源键弹出的对话框中添加一个重启选项了。当然这仅仅是添加一个显示而已,接下来就为这个选项添加逻辑控制代码了。
在上面的代码中使用的mWindowManagerFuncs.reboot方法和R.string.global_action_reboot资源(资源的添加放到最后说),默认是不存在的,所以需要在自己手动添加。
2、首先在找到WindowManagerFuncs这个所在的位置,在frameworks\base\core\java\android\view\WindowManagerPolicy.java中 [java]  view plain copy
  1. public interface WindowManagerFuncs {  
  2.        public static final int LID_ABSENT = -1;  
  3.        public static final int LID_CLOSED = 0;  
  4.        public static final int LID_OPEN = 1;  
  5.   
  6.        /** 
  7.         * Ask the window manager to re-evaluate the system UI flags. 
  8.         */  
  9.        public void reevaluateStatusBarVisibility();  
  10.   
  11.        /** 
  12.         * Add a fake window to the window manager.  This window sits 
  13.         * at the top of the other windows and consumes events. 
  14.         */  
  15.        public FakeWindow addFakeWindow(Looper looper,  
  16.                InputEventReceiver.Factory inputEventReceiverFactory,  
  17.                String name, int windowType, int layoutParamsFlags, boolean canReceiveKeys,  
  18.                boolean hasFocus, boolean touchFullscreen);  
  19.   
  20.        /** 
  21.         * Returns a code that describes the current state of the lid switch. 
  22.         */  
  23.        public int getLidState();  
  24.   
  25.        /** 
  26.         * Creates an input channel that will receive all input from the input dispatcher. 
  27.         */  
  28.        public InputChannel monitorInput(String name);  
  29.   
  30.        /** 
  31.         * Switch the keyboard layout for the given device. 
  32.         * Direction should be +1 or -1 to go to the next or previous keyboard layout. 
  33.         */  
  34.        public void switchKeyboardLayout(int deviceId, int direction);  
  35.   
  36.        public void shutdown();  
  37.        public void rebootSafeMode();  
  38. //edited by ouyang  
  39. public void reboot(boolean confirm);  
  40.    }  
添加reboot方法。但这只是添加接口而已,它的具体实现在呢?找了许久在frameworks\base\services\java\com\android\server\wm\windowManagerService.java中找到了这个接口的实现。

在该类中加入reboot()方法,该方法调用ShutdownThread的reboot方法 [java]  view plain copy
  1. // Called by window manager policy.  Not exposed externally.  
  2.   @Override  
  3.   public void shutdown() {  
  4.       ShutdownThread.shutdown(mContext, true);  
  5.   }  
  6.   //edited by ouyang start    
  7.   public void reboot(boolean confirm){  
  8. hutdownThread.reboot(mContext,null,confirm);      
  9.   }  
  10.   //edited by ouyang end      

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

[java]  view plain copy
  1. /** 
  2.     * Request a clean shutdown, waiting for subsystems to clean up their 
  3.     * state etc.  Must be called from a Looper thread in which its UI 
  4.     * is shown. 
  5.     * 
  6.     * @param context Context used to display the shutdown progress dialog. 
  7.     * @param reason code to pass to the kernel (e.g. "recovery"), or null. 
  8.     * @param confirm true if user confirmation is needed before shutting down. 
  9.     */  
  10.    public static void reboot(final Context context, String reason, boolean confirm) {  
  11.        mReboot = true;  
  12.        mRebootSafeMode = false;  
  13.        mRebootReason = reason;  
  14.        shutdownInner(context, confirm);  
  15.    }  


其中提供了一个静态的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方法



[java]  view plain copy
  1. static void shutdownInner(final Context context, boolean confirm) {  
  2.        // ensure that only one thread is trying to power down.  
  3.        // any additional calls are just returned  
  4.        synchronized (sIsStartedGuard) {  
  5.            if (sIsStarted) {  
  6.                Log.d(TAG, "Request to shutdown already running, returning.");  
  7.                return;  
  8.            }  
  9.        }  
  10.   
  11.        final int longPressBehavior = context.getResources().getInteger(  
  12.                        com.android.internal.R.integer.config_longPressOnPowerBehavior);  
  13. //edited by ouyang started  
  14. final int resourceId =mReboot  
  15. ?com.android.internal.R.string.reboot_confirm  
  16. :(mRebootSafeMode  
  17.                ? com.android.internal.R.string.reboot_safemode_confirm  
  18.                : (longPressBehavior == 2  
  19.                        ? com.android.internal.R.string.shutdown_confirm_question  
  20.                        : com.android.internal.R.string.shutdown_confirm));   
  21. //edited by ouyang ended    
  22.       
  23.        /** 
  24. //resource code 
  25. final int resourceId = mRebootSafeMode 
  26.                ? com.android.internal.R.string.reboot_safemode_confirm 
  27.                : (longPressBehavior == 2 
  28.                        ? com.android.internal.R.string.shutdown_confirm_question 
  29.                        : com.android.internal.R.string.shutdown_confirm); 
  30. */  
  31.        Log.d(TAG, "Notifying thread to start shutdown longPressBehavior=" + longPressBehavior);  
  32.   
  33.        if (confirm) {  
  34.            final CloseDialogReceiver closer = new CloseDialogReceiver(context);  
  35.            final AlertDialog dialog = new AlertDialog.Builder(context)  
  36.         /*   
  37.         //source code 
  38.                    .setTitle(mRebootSafeMode 
  39.                            ? com.android.internal.R.string.reboot_safemode_title 
  40.                            : com.android.internal.R.string.power_off) 
  41.                    .setMessage(resourceId) 
  42.         */  
  43.         //edited by ouyang started  
  44.                    .setTitle(mReboot  
  45.                        ?com.android.internal.R.string.global_action_reboot  
  46.                        :(mRebootSafeMode  
  47.                            ? com.android.internal.R.string.reboot_safemode_title  
  48.                            : com.android.internal.R.string.power_off))  
  49.                    .setMessage(resourceId)  
  50.                    //edited by ouyang ended   
  51.   
  52.                    .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {  
  53.                        public void onClick(DialogInterface dialog, int which) {  
  54.                            beginShutdownSequence(context);  
  55.                        }  
  56.                    })  
  57.                    .setNegativeButton(com.android.internal.R.string.no, null)  
  58.                    .create();  
  59.            closer.dialog = dialog;  
  60.            dialog.setOnDismissListener(closer);  
  61.            dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);  
  62.            dialog.show();  
  63.        } else {  
  64.            beginShutdownSequence(context);  
  65.        }  
  66.    }  

至此关于代码部分的改动全部完成,接下就添加需要添加使用到的资源了,就是其中使用的字符串,为了简单起见就添加了英文和简体中文: 在对应的资源文件中添加: frameworks\base\core\res\res\values\strings.xml
[html]  view plain copy
  1.   
  2.    <string name="global_action_reboot">Rebootstring>  
  3.    <string name="reboot_confirm">Do you want to reboot your device?string>      
  4.      
frameworks\base\core\res\res\values-zh-rCN\ strings.xml
[html]  view plain copy
  1.   
  2.     <string name="global_action_reboot">重启string>  
  3.     <string name="reboot_confirm">您要重新启动您的设备吗?string>             
  4.       

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



最后重新编译即可


http://blog.csdn.net/ouyang_peng/article/details/9945251

更多相关文章

  1. 浅谈Java中Collections.sort对List排序的两种方法
  2. Python list sort方法的具体使用
  3. python list.sort()根据多个关键字排序的方法实现
  4. android上一些方法的区别和用法的注意事项
  5. Android(安卓)Activity界面切换添加动画特效
  6. android实现字体闪烁动画的方法
  7. Android中dispatchDraw分析
  8. "Failed to fetch URL https://dl-ssl.google.com/android/repos
  9. android studio Could not find com.android.support.constraint

随机推荐

  1. 将要更新到android 4.0的手机列表
  2. Android(安卓)系统概要 ——《第一行代码
  3. android访问服务器端上传及服务器端接收
  4. Android的View类介绍-android的学习之旅(
  5. android CTS测试
  6. Qt on Android:将Qt调试信息输出到logcat
  7. 小熊android学习总结:Linux内核怎样启动An
  8. Android(安卓)call setting 源码分析 从
  9. 最封闭的开源系统:话说 Android(安卓)的八
  10. 【Android(安卓)FFMPEG 开发】Android(安