1. 前言

Android 6.0源码编译出来的系统中,没有长按电源键后显示重启按钮的功能,因此需要我们修改添加一下。

2. 分析

可参照关机的流程顺藤摸瓜,比葫芦画瓢添加重启功能。
下面列一下需要修改的文件:

# 需要修改的文件
frameworks/base/core/res/res/values/strings.xml
frameworks/base/core/res/res/values/config.xml
frameworks/base/core/res/res/values-zh-rCN/strings.xml
frameworks/base/core/res/res/values/public.xml
frameworks/base/core/res/res/values/symbols.xml
frameworks/base/core/res/res/drawable/ic_lock_power_reboot.xml
frameworks/base/services/core/java/com/android/server/policy/GlobalActions.java
frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java

# 需要添加的文件,及重启图标,网上搜索一个即可,注意要添加不同分辨率的图标
frameworks/base/core/res/res/drawable-xxhdpi/ic_lock_power_reboot_alpha.png
frameworks/base/core/res/res/drawable-xhdpi/ic_lock_power_reboot_alpha.png
frameworks/base/core/res/res/drawable-mdpi/ic_lock_power_reboot_alpha.png
frameworks/base/core/res/res/drawable-ldpi/ic_lock_power_reboot_alpha.png
frameworks/base/core/res/res/drawable-hdpi/ic_lock_power_reboot_alpha.png

# api更新文件, 在framework/base/core中添加、修改了东西
# 因此需要执行make update-api来生成新的doc文件
frameworks/base/api/system-current.txt
frameworks/base/api/current.txt

3. 方法

详细修改方法如下,在两个注释之间即为修改的地方:

a. frameworks/base/core/res/res/values/strings.xml

<!-- Shutdown Confirmation Dialog.  Message in the confirmation dialog
         when the user asks to reboot into safe mode. [CHAR LIMIT=NONE] -->
    <string name="reboot_safemode_confirm">Do you want to reboot into safe mode?
         This will disable all third party applications you have installed.
         They will be restored when you reboot again.</string>
     
    <!-- 需要添加的代码 -->
	<!-- label for item that reboots the phone in phone options dialog -->
	<string name="global_action_reboot">Reboot</string>	 
	<!-- Title of dialog to confirm rebooting. -->
	<string name="reboot_title">Reboot</string>
	
	<!-- Reboot Confirmation Dialog.  When the user chooses to reboot the device, there will
         be a confirmation dialog.  This is the message. -->
	<string name="reboot_confirm" product="tablet">Your tablet will reboot.</string>
	<string name="reboot_confirm" product="default">Your phone will reboot.</string>
	<!-- 添加结束 -->
	
    <!-- Recent Tasks dialog: title
     TODO: this should move to SystemUI.apk, but the code for the old
            recent dialog is still in the framework
     -->
    <string name="recent_tasks_title">Recent</string>

b. frameworks/base/core/res/res/values-zh-rCN/strings.xml

<string name="reboot_safemode_title" msgid="7054509914500140361">"重新启动并进入安全模式"</string>
    <string name="reboot_safemode_confirm" msgid="55293944502784668">"您要重新启动并进入安全模式吗?这样会停用您已安装的所有第三方应用。再次重新启动将恢复这些应用。"</string>
    
    <!-- 需要添加的代码 -->
	<string name="global_action_reboot">重启</string>
    <string name="reboot_title">"重启"</string>
	<string name="reboot_confirm" product="tablet">"您的平板电脑将会重启。"</string>
	<string name="reboot_confirm" product="default">"您的手机将会重启。"</string>
	<!-- 添加结束 -->
	
	<string name="recent_tasks_title" msgid="3691764623638127888">"近期任务"</string>
    <string name="no_recent_tasks" msgid="8794906658732193473">"最近没有运行任何应用"</string>
    <string name="global_actions" product="tablet" msgid="408477140088053665">"平板电脑选项"</string>
    <string name="global_actions" product="tv" msgid="7240386462508182976">"电视选项"</string>

c. frameworks/base/core/res/res/values/config.xml

<string-array translatable="false" name="config_globalActionsList">
        <item>power</item>
        <!-- 需要添加的代码 -->
		<item>reboot</item>
		<!-- 添加结束 -->
        <item>bugreport</item>
        <item>users</item>
    </string-array>

d. frameworks/base/core/res/res/drawable/ic_lock_power_reboot.xml 此布局文件不存在,需要添加。

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@drawable/ic_lock_power_reboot_alpha"
    android:tint="?attr/colorControlNormal" />

e. frameworks/base/core/res/res/values/public.xml

<public type="drawable" name="ic_lock_idle_alarm" id="0x0108002e" />
  <public type="drawable" name="ic_lock_lock" id="0x0108002f" />
  <public type="drawable" name="ic_lock_power_off" id="0x01080030" />
  
  <!-- 需要添加的代码 -->
  <public type="drawable" name="ic_lock_power_reboot" id="0x0108009e" />
  <!-- 添加结束 -->
  
  <public type="drawable" name="ic_lock_silent_mode" id="0x01080031" />
  <public type="drawable" name="ic_lock_silent_mode_off" id="0x01080032" />

f. frameworks/base/core/res/res/values/symbols.xml

<java-symbol type="string" name="reboot_to_update_reboot" />
  <java-symbol type="string" name="reboot_to_reset_title" />
  <java-symbol type="string" name="reboot_to_reset_message" />
  
  <!-- 需要添加的代码 -->
  <java-symbol type="string" name="reboot_confirm" />
  <java-symbol type="string" name="reboot_title" />
  <!-- 添加结束 -->
  
  <java-symbol type="string" name="reboot_safemode_confirm" />
  <java-symbol type="string" name="reboot_safemode_title" />
  <java-symbol type="string" name="relationTypeAssistant" />

g. frameworks/base/services/core/java/com/android/server/policy/GlobalActions.java

import android.database.ContentObserver;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.net.ConnectivityManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
// 需要添加的代码
import android.os.IPowerManager;
// 添加结束
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;

................

class GlobalActions implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener  {

	................

    private static final String GLOBAL_ACTION_KEY_POWER = "power";
    
    // 需要添加的代码
	private static final String GLOBAL_ACTION_KEY_REBOOT = "reboot";
	// 添加结束
	
    private static final String GLOBAL_ACTION_KEY_AIRPLANE = "airplane";
    private static final String GLOBAL_ACTION_KEY_BUGREPORT = "bugreport";
    private static final String GLOBAL_ACTION_KEY_SILENT = "silent";
    private static final String GLOBAL_ACTION_KEY_USERS = "users";
    private static final String GLOBAL_ACTION_KEY_SETTINGS = "settings";
    private static final String GLOBAL_ACTION_KEY_LOCKDOWN = "lockdown";
    private static final String GLOBAL_ACTION_KEY_VOICEASSIST = "voiceassist";
    private static final String GLOBAL_ACTION_KEY_ASSIST = "assist";

	................

	if (GLOBAL_ACTION_KEY_POWER.equals(actionKey)) {
		mItems.add(new PowerAction());
	
	// 需要添加的代码
	} else if (GLOBAL_ACTION_KEY_REBOOT.equals(actionKey)) {
		Log.d(TAG,"add reboot actions");
		mItems.add(new RebootAction());
	// 添加结束
	
	} else if (GLOBAL_ACTION_KEY_AIRPLANE.equals(actionKey)) {


	................

	// 需要添加的代码
	private final class RebootAction extends SinglePressAction {
		private RebootAction() {
			super(com.android.internal.R.drawable.ic_lock_power_reboot,
				R.string.global_action_reboot);
		}
		
        @Override
        public boolean showDuringKeyguard() {
            return true;
        }
		
        @Override
        public boolean showBeforeProvisioning() {
            return true;
        }

        @Override
        public void onPress() {
            try {
                IPowerManager pm = IPowerManager.Stub.asInterface(ServiceManager
                        .getService(Context.POWER_SERVICE));
                pm.reboot(true, null, false);
            } catch (RemoteException e) {
                Log.e(TAG, "PowerManager service died!", e);
                return;
            }
        }		
	}
	// 添加结束
	
    private Action getBugReportAction() {

h. frameworks/base/services/core/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 confirm true if user confirmation is needed before shutting down.
     */
    public static void shutdown(final Context context, boolean confirm) {
        mReboot = false;
        mRebootSafeMode = false;
        shutdownInner(context, confirm);
    }

    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;
            }
        }
        
		// 需要添加的代码
		boolean showRebootOption = false;
		String[] defaultActions = context.getResources().getStringArray(
			com.android.internal.R.array.config_globalActionsList);
		for (int i = 0; i < defaultActions.length; i++) {
			if (defaultActions[i].equals("reboot")) {
				showRebootOption = true;
				break;
			}
		}
		// 添加结束
		
        final int longPressBehavior = context.getResources().getInteger(
                        com.android.internal.R.integer.config_longPressOnPowerBehavior);
        
        // 需要添加的代码
        //final int resourceId = mRebootSafeMode
		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);
		
		// 需要添加的代码
		if (showRebootOption && !mRebootSafeMode) {
			resourceId = com.android.internal.R.string.reboot_confirm;
		}
		// 添加结束
		
        Log.d(TAG, "Notifying thread to start shutdown longPressBehavior=" + longPressBehavior);

        if (confirm) {
            final CloseDialogReceiver closer = new CloseDialogReceiver(context);
            if (sConfirmDialog != null) {
                sConfirmDialog.dismiss();
            }
            sConfirmDialog = new AlertDialog.Builder(context)
                    .setTitle(mRebootSafeMode
                            ? com.android.internal.R.string.reboot_safemode_title
                            
                            // 需要添加的代码
                            : showRebootOption
								? com.android.internal.R.string.reboot_title
								: com.android.internal.R.string.power_off)
							// 添加结束
							
                    .setMessage(resourceId)
                    .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 = sConfirmDialog;
            sConfirmDialog.setOnDismissListener(closer);
            sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
            sConfirmDialog.show();
        } else {
            beginShutdownSequence(context);
        }
    }

4. 备注

a. 编译问题
更新了framework/base/core里面的内容后,需要执行make update-api来更新doc,将生成的current.txtsystem-current.txt一并提交代码仓库,下次编译直接从代码仓库更新代码即可。

b. drawable-xxx目录下图标问题
如果暂时找不到重启图标,可以临时使用关机图标,需要修改ic_lock_power_reboot.xmlGlobalActions.java,将其资源指向重启图标即可。