rk3288 + Android 7.1
1. 导航栏增加电源按键, 点击后打开关机菜单
2. 关机菜单项增加休眠项, 点击后进休眠
//修改
modified: frameworks/base/core/java/android/view/WindowManagerPolicy.java
modified: frameworks/base/core/res/res/values/config.xml
modified: frameworks/base/core/res/res/values/strings.xml
modified: frameworks/base/core/res/res/values/symbols.xml
modified: frameworks/base/packages/SystemUI/res/values-sw600dp/config.xml
modified: frameworks/base/packages/SystemUI/res/values-sw900dp/config.xml
modified: frameworks/base/packages/SystemUI/res/values/config.xml
modified: frameworks/base/packages/SystemUI/res/values/strings.xml
modified: frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
modified: frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
modified: frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
modified: frameworks/base/services/core/java/com/android/server/policy/GlobalActions.java
modified: frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
modified: frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
//新增
frameworks/base/core/res/res/drawable/ic_sleep.xml
frameworks/base/packages/SystemUI/res/drawable-nodpi/ic_sysbar_power.png
frameworks/base/packages/SystemUI/res/layout/power.xml
准备好对应的图标和相关的字符:
frameworks/base/packages/SystemUI/res/drawable-nodpi/ic_sysbar_power.png
|-- frameworks/base/packages/SystemUI/res/values/strings.xml
<string name="accessibility_power" translatable="false">Powerstring>
增加按键layout.
|-- frameworks/base/packages/SystemUI/res/layout/power.xml
<com.android.systemui.statusbar.policy.KeyButtonView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:systemui="http://schemas.android.com/apk/res-auto"
android:id="@+id/power"
android:layout_width="@dimen/navigation_key_width"
android:layout_height="match_parent"
android:layout_weight="0"
android:src="@drawable/ic_sysbar_power"
systemui:keyCode="0"
android:scaleType="center"
android:contentDescription="@string/accessibility_power"
android:paddingStart="@dimen/navigation_key_padding"
android:paddingEnd="@dimen/navigation_key_padding"
/>
其中, keyCode是按键值, 若不想处理为按键, 则置为0
|-- frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
public static final String POWER = "power";
//加载按键
@Override
protected void onFinishInflate() {
super.onFinishInflate();
inflateChildren();
clearViews();
inflateLayout(getDefaultLayout());
}
//默认按键
protected String getDefaultLayout() {
return mContext.getString(R.string.config_navBarLayout);
}
protected void inflateLayout(String newLayout) {
mCurrentLayout = newLayout;
if (newLayout == null) {
newLayout = getDefaultLayout();
}
String[] sets = newLayout.split(GRAVITY_SEPARATOR, 3);
String[] start = sets[0].split(BUTTON_SEPARATOR);
String[] center = sets[1].split(BUTTON_SEPARATOR);
String[] end = sets[2].split(BUTTON_SEPARATOR);
// Inflate these in start to end order or accessibility traversal will be messed up.
inflateButtons(start, (ViewGroup) mRot0.findViewById(R.id.ends_group), isRot0Landscape);
inflateButtons(start, (ViewGroup) mRot90.findViewById(R.id.ends_group), !isRot0Landscape);
LinearLayout centerLayout = (LinearLayout)mRot0.findViewById(R.id.center_group);
mIsReverseInflateRot0 = !isRot0Landscape && !isSw600Dp() && mCurrentOrientation == Configuration.ORIENTATION_LANDSCAPE;
if(mIsReverseInflateRot0)
centerLayout.setOrientation(LinearLayout.VERTICAL);
inflateButtons(center, centerLayout, isRot0Landscape);
mIsReverseInflateRot0 = false;
centerLayout = (LinearLayout)mRot90.findViewById(R.id.center_group);
mIsReverseInflateRot90 = !isRot0Landscape && !isSw600Dp() && mCurrentOrientation == Configuration.ORIENTATION_PORTRAIT;
if(mIsReverseInflateRot90)
centerLayout.setOrientation(LinearLayout.HORIZONTAL);
inflateButtons(center, centerLayout, !isRot0Landscape);
mIsReverseInflateRot90 = false;
addGravitySpacer((LinearLayout) mRot0.findViewById(R.id.ends_group));
addGravitySpacer((LinearLayout) mRot90.findViewById(R.id.ends_group));
inflateButtons(end, (ViewGroup) mRot0.findViewById(R.id.ends_group), isRot0Landscape);
inflateButtons(end, (ViewGroup) mRot90.findViewById(R.id.ends_group), !isRot0Landscape);
}
//加入导航栏
@Nullable
protected View inflateButton(String buttonSpec, ViewGroup parent, boolean landscape) {
LayoutInflater inflater = landscape ? mLandscapeInflater : mLayoutInflater;
float size = extractSize(buttonSpec);
String button = extractButton(buttonSpec);
View v = null;
if (HOME.equals(button)) {
v = inflater.inflate(R.layout.home, parent, false);
if (landscape && isSw600Dp()) {
setupLandButton(v);
}
} else if (BACK.equals(button)) {
v = inflater.inflate(R.layout.back, parent, false);
if (landscape && isSw600Dp()) {
setupLandButton(v);
}
} else if (RECENT.equals(button)) {
v = inflater.inflate(R.layout.recent_apps, parent, false);
if (landscape && isSw600Dp()) {
setupLandButton(v);
}
} else if (SCREENSHOT.equals(button)) {
v = inflater.inflate(R.layout.screenshot, parent, false);
if (landscape && isSw600Dp()) {
setupLandButton(v);
}
//下面增加POWER按键, layout.power.xml也是在这里使用
}else if (POWER.equals(button)) {
v = inflater.inflate(R.layout.power, parent, false);
if (landscape && isSw600Dp()) {
setupLandButton(v);
}
} else if (VOLUME_ADD.equals(button)) {
v = inflater.inflate(R.layout.volume_add, parent, false);
if (landscape && isSw600Dp()) {
setupLandButton(v);
}
} else if (VOLUME_SUB.equals(button)) {
v = inflater.inflate(R.layout.volume_sub, parent, false);
if (landscape && isSw600Dp()) {
setupLandButton(v);
}
} else if (MENU_IME.equals(button)) {
v = inflater.inflate(R.layout.menu_ime, parent, false);
} else if (NAVSPACE.equals(button)) {
v = inflater.inflate(R.layout.nav_key_space, parent, false);
} else if (CLIPBOARD.equals(button)) {
v = inflater.inflate(R.layout.clipboard, parent, false);
} else if (button.startsWith(KEY)) {
String uri = extractImage(button);
int code = extractKeycode(button);
v = inflater.inflate(R.layout.custom_key, parent, false);
((KeyButtonView) v).setCode(code);
if (uri != null) {
((KeyButtonView) v).loadAsync(uri);
}
} else {
return null;
}
if (size != 0) {
ViewGroup.LayoutParams params = v.getLayoutParams();
params.width = (int) (params.width * size);
}
if(mIsReverseInflateRot0 || mIsReverseInflateRot90){
setupVerticalButton(v);
}
parent.addView(v);
addToDispatchers(v);
View lastView = landscape ? mLastLandscape : mLastPortrait;
if (lastView != null) {
v.setAccessibilityTraversalAfter(lastView.getId());
}
if (landscape) {
mLastLandscape = v;
} else {
mLastPortrait = v;
}
return v;
}
默认按键布局config_navBarLayout定义:
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java: return mContext.getString(R.string.config_navBarLayout);
frameworks/base/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java: navLayout = context.getString(R.string.config_navBarLayout);
frameworks/base/packages/SystemUI/res/values/config.xml: space;volume_sub,back,home,recent,volume_add,screenshot;menu_ime
frameworks/base/packages/SystemUI/res/values-sw600dp/config.xml: space;volume_sub,back,home,recent,volume_add,screenshot;menu_ime
frameworks/base/packages/SystemUI/res/values-sw900dp/config.xml: space;volume_sub,back,home,recent,volume_add,screenshot;menu_ime
增加power的个改:
diff --git a/frameworks/base/packages/SystemUI/res/values-sw600dp/config.xml b/frameworks/base/packages/SystemUI/res/values-sw600dp/config.xml
old mode 100644
new mode 100755
index aa03ab2..ef41fee
--- a/frameworks/base/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/frameworks/base/packages/SystemUI/res/values-sw600dp/config.xml
@@ -34,7 +34,7 @@
true
- space;volume_sub,back,home,recent,volume_add,screenshot;menu_ime
+ space;volume_sub,back,home,recent,volume_add,screenshot,power;menu_ime
290
diff --git a/frameworks/base/packages/SystemUI/res/values-sw900dp/config.xml b/frameworks/base/packages/SystemUI/res/values-sw900dp/config.xml
old mode 100644
new mode 100755
index 016f7e5..c992349
--- a/frameworks/base/packages/SystemUI/res/values-sw900dp/config.xml
+++ b/frameworks/base/packages/SystemUI/res/values-sw900dp/config.xml
@@ -19,6 +19,6 @@
- space;volume_sub,back,home,recent,volume_add,screenshot;menu_ime
+ space;volume_sub,back,home,recent,volume_add,screenshot,power;menu_ime
diff --git a/frameworks/base/packages/SystemUI/res/values/config.xml b/frameworks/base/packages/SystemUI/res/values/config.xml
old mode 100644
new mode 100755
index da5f4bf..59e7161
--- a/frameworks/base/packages/SystemUI/res/values/config.xml
+++ b/frameworks/base/packages/SystemUI/res/values/config.xml
@@ -280,7 +280,7 @@
com.android.systemui.SystemUIFactory
- space;volume_sub,back,home,recent,volume_add,screenshot;menu_ime
+ space;volume_sub,back,home,recent,volume_add,screenshot,power;menu_ime
false
添加触摸事件设置按键可见:
|-- frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
//点击处理:
private View.OnClickListener mPowerClickListener = new View.OnClickListener(){
public void onClick(View v){
Intent intent = new Intent("android.intent.action.POWER_MENU");
mContext.sendBroadcast(intent);
}
};
private void prepareNavigationBarView() {
mNavigationBarView.reorient();
ButtonDispatcher recentsButton = mNavigationBarView.getRecentsButton();
recentsButton.setOnClickListener(mRecentsClickListener);
recentsButton.setOnTouchListener(mRecentsPreloadOnTouchListener);
recentsButton.setLongClickable(true);
recentsButton.setOnLongClickListener(this::handleLongPressBackRecents);
ButtonDispatcher backButton = mNavigationBarView.getBackButton();
backButton.setLongClickable(true);
backButton.setOnLongClickListener(this::handleLongPressBackRecents);
ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
homeButton.setOnTouchListener(mHomeActionListener);
homeButton.setOnLongClickListener(mLongPressHomeListener);
ButtonDispatcher screenshotButton=mNavigationBarView.getScreenshotButton();
screenshotButton.setOnClickListener(mScreenshotClickListener);
screenshotButton.setOnTouchListener(mScreenshotTouchListener);
screenshotButton.setVisibility(View.VISIBLE);
boolean isShow=Settings.System.getInt(mContext.getContentResolver(), Settings.System.SCREENSHOT_BUTTON_SHOW, 1)==1;
if(isShow){
screenshotButton.setVisibility(View.VISIBLE);
}else{
screenshotButton.setVisibility(View.GONE);
}
//添加监听并使用按键可见.
ButtonDispatcher powerButton=mNavigationBarView.getPowerButton();
powerButton.setOnClickListener(mPowerClickListener);
//powerButton.setOnTouchListener(mPowerTouchListener);
powerButton.setVisibility(View.VISIBLE);
...
}
|-- frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
public NavigationBarView(Context context, AttributeSet attrs) {
super(context, attrs);
mDisplay = ((WindowManager) context.getSystemService(
Context.WINDOW_SERVICE)).getDefaultDisplay();
mVertical = false;
mShowMenu = false;
mGestureHelper = new NavigationBarGestureHelper(context);
mConfiguration = new Configuration();
mConfiguration.updateFrom(context.getResources().getConfiguration());
updateIcons(context, Configuration.EMPTY, mConfiguration);
mBarTransitions = new NavigationBarTransitions(this);
mButtonDisatchers.put(R.id.back, new ButtonDispatcher(R.id.back));
mButtonDisatchers.put(R.id.home, new ButtonDispatcher(R.id.home));
mButtonDisatchers.put(R.id.recent_apps, new ButtonDispatcher(R.id.recent_apps));
mButtonDisatchers.put(R.id.menu, new ButtonDispatcher(R.id.menu));
mButtonDisatchers.put(R.id.ime_switcher, new ButtonDispatcher(R.id.ime_switcher));
mButtonDisatchers.put(R.id.screenshot, new ButtonDispatcher(R.id.screenshot));
//添加到集合.
mButtonDisatchers.put(R.id.power, new ButtonDispatcher(R.id.power));
mButtonDisatchers.put(R.id.volume_add, new ButtonDispatcher(R.id.volume_add));
mButtonDisatchers.put(R.id.volume_sub, new ButtonDispatcher(R.id.volume_sub));
}
//供外部调用
public ButtonDispatcher getPowerButton() {
return mButtonDisatchers.get(R.id.power);
}
至此, 按键添加完成, 在点击后, 会发送广播 android.intent.action.POWER_MENU
准备资源:
frameworks/base/core/res/res/drawable/ic_sleep.xml
|-- frameworks/base/core/res/res/values/strings.xml
diff --git a/frameworks/base/core/res/res/values/strings.xml b/frameworks/base/core/res/res/values/strings.xml
old mode 100644
new mode 100755
index 4172864..89d45d7
--- a/frameworks/base/core/res/res/values/strings.xml
+++ b/frameworks/base/core/res/res/values/strings.xml
@@ -496,6 +496,9 @@
<string name="global_action_power_off">Power offstring>
+
+ <string name="global_action_sleep">Sleepstring>
frameworks/base/core/res/res/values/symbols.xml
diff --git a/frameworks/base/core/res/res/values/symbols.xml b/frameworks/base/core/res/res/values/symbols.xml
old mode 100644
new mode 100755
index 81d06af..02815a2
--- a/frameworks/base/core/res/res/values/symbols.xml
+++ b/frameworks/base/core/res/res/values/symbols.xml
@@ -1607,6 +1607,7 @@
<java-symbol type="string" name="faceunlock_multiple_failures" />
<java-symbol type="string" name="global_action_power_off" />
<java-symbol type="string" name="global_action_restart" />
+ <java-symbol type="string" name="global_action_sleep" />
<java-symbol type="string" name="global_actions_airplane_mode_off_status" />
<java-symbol type="string" name="global_actions_airplane_mode_on_status" />
<java-symbol type="string" name="global_actions_toggle_airplane_mode" />
@@ -2734,6 +2735,7 @@
<java-symbol type="array" name="config_defaultFirstUserRestrictions" />
<java-symbol type="drawable" name="ic_restart" />
+ <java-symbol type="drawable" name="ic_sleep" />
frameworks/base/core/res/res/values/config.xml
diff --git a/frameworks/base/core/res/res/values/config.xml b/frameworks/base/core/res/res/values/config.xml
old mode 100644
new mode 100755
index e4839d7..935110a
--- a/frameworks/base/core/res/res/values/config.xml
+++ b/frameworks/base/core/res/res/values/config.xml
@@ -2209,6 +2209,7 @@
<string-array translatable="false" name="config_globalActionsList">
<item>poweritem>
<item>restartitem>
+ <item>sleepitem>
<item>bugreportitem>
<item>usersitem>
string-array>
删除生成中间文件:
rm -rf out/target/product/rk3288/system/framework/framework-res.apk out/target/product/rk3288/obj/APPS/framework-res_intermediates out/target/product/rk3288/obj/NOTICE_FILES/src/system/framework/framework-res.apk.txt out/target/product/rk3288/obj/PACKAGING/target_files_intermediates/rk3288-target_files-eng.anson/SYSTEM/framework/framework-res.apk out/target/common/obj/APPS/framework-res_intermediates
重新编译
mmm frameworks/base/core/res/ -j4
增加sleep接口
|-- 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;
public static final int CAMERA_LENS_COVER_ABSENT = -1;
public static final int CAMERA_LENS_UNCOVERED = 0;
public static final int CAMERA_LENS_COVERED = 1;
/**
* Ask the window manager to re-evaluate the system UI flags.
*/
public void reevaluateStatusBarVisibility();
/**
* Add a input consumer which will consume all input events going to any window below it.
*/
public InputConsumer addInputConsumer(Looper looper,
InputEventReceiver.Factory inputEventReceiverFactory);
/**
* Returns a code that describes the current state of the lid switch.
*/
public int getLidState();
/**
* Lock the device now.
*/
public void lockDeviceNow();
/**
* Returns a code that descripbes whether the camera lens is covered or not.
*/
public int getCameraLensCoverState();
/**
* Switch the input method, to be precise, input method subtype.
*
* @param forwardDirection {@code true} to rotate in a forward direction.
*/
public void switchInputMethod(boolean forwardDirection);
public void shutdown(boolean confirm);
public void reboot(boolean confirm);
public void rebootSafeMode(boolean confirm);
//增加
public void sleep();
}
实现sleep:
|-- frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
...
// Called by window manager policy. Not exposed externally.
@Override
public void shutdown(boolean confirm) {
ShutdownThread.shutdown(mContext, PowerManager.SHUTDOWN_USER_REQUESTED, confirm);
}
// Called by window manager policy. Not exposed externally.
@Override
public void reboot(boolean confirm) {
ShutdownThread.reboot(mContext, PowerManager.SHUTDOWN_USER_REQUESTED, confirm);
}
// Called by window manager policy. Not exposed externally.
@Override
public void rebootSafeMode(boolean confirm) {
ShutdownThread.rebootSafeMode(mContext, confirm);
}
//实现sleep, 调用PowerManager.goToSleep.
@Override
public void sleep(){
mPowerManager.goToSleep(SystemClock.uptimeMillis());
}
...
}
增加sleep项
|-- frameworks/base/services/core/java/com/android/server/policy/GlobalActions.java
private static final String GLOBAL_ACTION_KEY_RESTART = "restart";
//增加sleep
private static final String GLOBAL_ACTION_KEY_SLEEP = "sleep";
private GlobalActionsDialog createDialog() {
...
//从xml中加载config_globalActionsList字符数组
mItems = new ArrayList<Action>();
String[] defaultActions = mContext.getResources().getStringArray(
com.android.internal.R.array.config_globalActionsList);
ArraySet<String> addedKeys = new ArraySet<String>();
for (int i = 0; i < defaultActions.length; i++) {
String actionKey = defaultActions[i];
if (addedKeys.contains(actionKey)) {
// If we already have added this, don't add it again.
continue;
}
if (GLOBAL_ACTION_KEY_POWER.equals(actionKey)) {
mItems.add(new PowerAction());
} else if (GLOBAL_ACTION_KEY_AIRPLANE.equals(actionKey)) {
mItems.add(mAirplaneModeOn);
} else if (GLOBAL_ACTION_KEY_BUGREPORT.equals(actionKey)) {
if (Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0 && isCurrentUserOwner()) {
mItems.add(new BugReportAction());
}
} else if (GLOBAL_ACTION_KEY_SILENT.equals(actionKey)) {
if (mShowSilentToggle) {
mItems.add(mSilentModeAction);
}
} else if (GLOBAL_ACTION_KEY_USERS.equals(actionKey)) {
if (SystemProperties.getBoolean("fw.power_user_switcher", false)) {
addUsersToMenu(mItems);
}
} else if (GLOBAL_ACTION_KEY_SETTINGS.equals(actionKey)) {
mItems.add(getSettingsAction());
} else if (GLOBAL_ACTION_KEY_LOCKDOWN.equals(actionKey)) {
mItems.add(getLockdownAction());
} else if (GLOBAL_ACTION_KEY_VOICEASSIST.equals(actionKey)) {
mItems.add(getVoiceAssistAction());
} else if (GLOBAL_ACTION_KEY_ASSIST.equals(actionKey)) {
mItems.add(getAssistAction());
} else if (GLOBAL_ACTION_KEY_RESTART.equals(actionKey)) {
mItems.add(new RestartAction());
//创建并添加SleepAction
} else if (GLOBAL_ACTION_KEY_SLEEP.equals(actionKey)){
mItems.add(new SleepAction());
} else {
Log.e(TAG, "Invalid global action key " + actionKey);
}
// Add here so we don't add more than one.
addedKeys.add(actionKey);
}
if (mEmergencyAffordanceManager.needsEmergencyAffordance()) {
mItems.add(getEmergencyAction());
}
mAdapter = new MyAdapter();
AlertParams params = new AlertParams(mContext);
params.mAdapter = mAdapter;
...
}
//增加SleepAction.
private final class SleepAction extends SinglePressAction implements LongPressAction {
private SleepAction() {
super(R.drawable.ic_sleep, R.string.global_action_sleep);
}
@Override
public boolean onLongPress() {
return false;
}
@Override
public boolean showDuringKeyguard() {
return true;
}
@Override
public boolean showBeforeProvisioning() {
return true;
}
@Override
public void onPress() {
//调用新增sleep函数
mWindowManagerFuncs.sleep();
}
}
接收从SystemUI发送过来的广播并调起GlobalActions.
|-- frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
/** {@inheritDoc} */
@Override
public void init(Context context, IWindowManager windowManager,
WindowManagerFuncs windowManagerFuncs) {
mContext = context;
mWindowManager = windowManager;
mWindowManagerFuncs = windowManagerFuncs;
...
// register for dream-related broadcasts
filter = new IntentFilter();
filter.addAction(Intent.ACTION_DREAMING_STARTED);
filter.addAction(Intent.ACTION_DREAMING_STOPPED);
context.registerReceiver(mDreamReceiver, filter);
filter = new IntentFilter();
filter.addAction(Intent.ACTION_SHUTDOWN);
context.registerReceiver(mShutdownanimationReceiver, filter);
// register for multiuser-relevant broadcasts
filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
context.registerReceiver(mMultiuserReceiver, filter);
//注册广播监听: android.intent.action.POWER_MENU
IntentFilter ifPower = new IntentFilter("android.intent.action.POWER_MENU");
context.registerReceiver(new BroadcastReceiver(){
@Override
public void onReceive(Context context, Intent intent) {
//show global actions dialog
showGlobalActionsInternal();
}
}, ifPower);
}