最近基于Android4.0,移植了一个长按返回键结束程序的功能。在这里分享一下。希望能对有需要的朋友有所帮助。
在正式开始移植工作之前,你需要了解:1、Android framework 编译以及反编译过程 2、有一定的Android开发基础和汇编知识(保证你能读懂Dalvik Code) 3、你能耐得住性子
Android4.0中,关于按键部分的功能实现在PhoneWindowManager中实现的。
第一步:
在#instance fields下增加
.field mBackKillTimeout:Z
.field mBackLongPress:Ljava/lang/Runnable;
在.method public constructor <init>()V中增加
new-instance v0, Lcom/android/internal/policy/impl/PhoneWindowManager$KillConcept;
invoke-direct {v0, p0}, Lcom/android/internal/policy/impl/PhoneWindowManager$KillConcept;-><init>(Lcom/android/internal/policy/impl/PhoneWindowManager;)V
iput-object v0, p0, Lcom/android/internal/policy/impl/PhoneWindowManager;->mBackLongPress:Ljava/lang/Runnable;
上面增加的代码翻译过来就是下面两行
boolean mBackKillTimeout;
Runnable mBackLongPress = new KillConcept();
第二步:这步是最复杂,也是最关键的一步
在.method public interceptKeyBeforeDispatching方法中增加
#Modify by wayne
:cond_37e
const/16 v28, 0x4
move/from16 v0, v28
move/from16 v1, v13
if-ne v1, v0, :cond_47e
.line 1863
move-object/from16 v0, p0
iget-boolean v0, v0, Lcom/android/internal/policy/impl/PhoneWindowManager;->mBackKillTimeout:Z
move/from16 v28, v0
if-nez v28, :cond_47e
if-eqz v6, :cond_47e
if-nez v18, :cond_47e
.line 1864
move-object/from16 v0, p0
iget-object v0, v0, Lcom/android/internal/policy/impl/PhoneWindowManager;->mHandler:Landroid/os/Handler;
move-object/from16 v23, v0
move-object/from16 v0, p0
iget-object v0, v0, Lcom/android/internal/policy/impl/PhoneWindowManager;->mBackLongPress:Ljava/lang/Runnable;
move-object/from16 v24, v0
invoke-static {}, Landroid/view/ViewConfiguration;->getGlobalActionKeyTimeout()J
move-result-wide v25
invoke-virtual/range {v23 .. v26}, Landroid/os/Handler;->postDelayed(Ljava/lang/Runnable;J)Z
.line 1865
const/16 v28, 0x1
move/from16 v0, v28
move-object/from16 v1, p0
iput-boolean v0, v1, Lcom/android/internal/policy/impl/PhoneWindowManager;->mBackKillTimeout:Z
#end modify
这里的插入点是在下面这段代码后:
if (mVolumeDownKeyTriggered && !mPowerKeyTriggered) {
final long now = SystemClock.uptimeMillis();
final long timeoutTime = mVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS;
if (now < timeoutTime) {
return timeoutTime - now;
}
}
插入的代码应该是:
if((keyCode == KeyEvent.KEYCODE_BACK) && (!down) && ((flags & KeyEvent.FLAG_CANCELED) == 0)) {
this.mHandler.removeCallbacks(this.mBackLongPress);
KeyEvent.changeFlags(paramKeyEvent, m + 32);
this.mBackKillTimeout = false;
}
接下来,我们还需要插入一段代码:
#Modify by wayne
:cond_37e
const/16 v28, 0x4
move/from16 v0, v28
move/from16 v1, v13
if-ne v1, v0, :cond_47e
.line 1863
move-object/from16 v0, p0
iget-boolean v0, v0, Lcom/android/internal/policy/impl/PhoneWindowManager;->mBackKillTimeout:Z
move/from16 v28, v0
if-nez v28, :cond_47e
if-eqz v6, :cond_47e
if-nez v18, :cond_47e
.line 1864
move-object/from16 v0, p0
iget-object v0, v0, Lcom/android/internal/policy/impl/PhoneWindowManager;->mHandler:Landroid/os/Handler;
move-object/from16 v23, v0
move-object/from16 v0, p0
iget-object v0, v0, Lcom/android/internal/policy/impl/PhoneWindowManager;->mBackLongPress:Ljava/lang/Runnable;
move-object/from16 v24, v0
invoke-static {}, Landroid/view/ViewConfiguration;->getGlobalActionKeyTimeout()J
move-result-wide v25
invoke-virtual/range {v23 .. v26}, Landroid/os/Handler;->postDelayed(Ljava/lang/Runnable;J)Z
.line 1865
const/16 v28, 0x1
move/from16 v0, v28
move-object/from16 v1, p0
iput-boolean v0, v1, Lcom/android/internal/policy/impl/PhoneWindowManager;->mBackKillTimeout:Z
#end modify
插入点是:
// Handle application launch keys.
if (down && repeatCount == 0 && !keyguardOn) {
String category = sApplicationLaunchKeyCategories.get(keyCode);
if (category != null) {
Intent intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, category);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
mContext.startActivity(intent);
} catch (ActivityNotFoundException ex) {
Slog.w(TAG, "Dropping application launch key because "
+ "the activity to which it is registered was not found: "
+ "keyCode=" + keyCode + ", category=" + category, ex);
}
return -1;
}
}
插入的代码是:
if(down && repeatCount == 0 && !this.mBackKillTimeout && keyCode == KeyEvent.KEYCODE_BACK) {
this.mHandler.postDelayed(this.mBackLongPress, ViewConfiguration.getGlobalActionKeyTimeout());
this.mBackKillTimeout = true;
}
第三步:新增一个内部类KillConcept,点击链接下载,解压缩后将得到的文件放在你反编译后的目录里。最后回编译为dex文件,检查没有错误后直接拖进并替换到android.policy.jar里,最后就是推送到系统里面啦。
下载地址:http://pan.baidu.com/share/link?shareid=436238&uk=3104024337
整个移植过程中,第二步是最复杂的地方。任何一个错误都可能会引起编译不通过,特别是使用的寄存器地址,因为不能保证每一台机器反编译出来的代码中都是使用的同样的寄存器地址,具体情况要具体分析。