Android长按关机键,会弹出关机的对话框,如下图:
现在分析一下详细的流程:
1) PWM中,会调用
- private void interceptPowerKeyDown(boolean handled) {
- mPowerKeyHandled = handled;
- if (!handled) {
- mHandler.postDelayed(mPowerLongPress, ViewConfiguration.getGlobalActionKeyTimeout());
- }
- }
private void interceptPowerKeyDown(boolean handled) {
mPowerKeyHandled = handled;
if (!handled) {
mHandler.postDelayed(mPowerLongPress, ViewConfiguration.getGlobalActionKeyTimeout());
}
}
从而进入mPowerLongPress
- private final Runnable mPowerLongPress = new Runnable() {
- @Override
- public void run() {
- // The context isn't read
- if (mLongPressOnPowerBehavior < 0) {
- mLongPressOnPowerBehavior = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_longPressOnPowerBehavior);
- }
- ...
- switch (resolvedBehavior) {
- case LONG_PRESS_POWER_NOTHING:
- break;
- case LONG_PRESS_POWER_GLOBAL_ACTIONS:
- mPowerKeyHandled = true;
- if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) {
- performAuditoryFeedbackForAccessibilityIfNeed();
- }
- sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
- showGlobalActionsDialog();
- break;
- ...
- }
- }
- };
private final Runnable mPowerLongPress = new Runnable() {
@Override
public void run() {
// The context isn't read
if (mLongPressOnPowerBehavior < 0) {
mLongPressOnPowerBehavior = mContext.getResources().getInteger(
com.android.internal.R.integer.config_longPressOnPowerBehavior);
}
...
switch (resolvedBehavior) {
case LONG_PRESS_POWER_NOTHING:
break;
case LONG_PRESS_POWER_GLOBAL_ACTIONS:
mPowerKeyHandled = true;
if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) {
performAuditoryFeedbackForAccessibilityIfNeed();
}
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
showGlobalActionsDialog();
break;
...
}
}
};
调用showGlobalActionsDialog
- void showGlobalActionsDialog() {
- if (mGlobalActions == null) {
- mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);
- }
- final boolean keyguardShowing = keyguardIsShowingTq();
- mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());
- if (keyguardShowing) {
- // since it took two seconds of long press to bring this up,
- // poke the wake lock so they have some time to see the dialog.
- mKeyguardMediator.userActivity();
- }
- }
void showGlobalActionsDialog() {
if (mGlobalActions == null) {
mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);
}
final boolean keyguardShowing = keyguardIsShowingTq();
mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());
if (keyguardShowing) {
// since it took two seconds of long press to bring this up,
// poke the wake lock so they have some time to see the dialog.
mKeyguardMediator.userActivity();
}
}
- public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {
- mKeyguardShowing = keyguardShowing;
- mDeviceProvisioned = isDeviceProvisioned;
- if (mDialog != null) {
- mDialog.dismiss();
- mDialog = null;
- // Show delayed, so that the dismiss of the previous dialog completes
- mHandler.sendEmptyMessage(MESSAGE_SHOW);
- } else {
- handleShow();
- }
- }
public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {
mKeyguardShowing = keyguardShowing;
mDeviceProvisioned = isDeviceProvisioned;
if (mDialog != null) {
mDialog.dismiss();
mDialog = null;
// Show delayed, so that the dismiss of the previous dialog completes
mHandler.sendEmptyMessage(MESSAGE_SHOW);
} else {
handleShow();
}
}
然后调用handleShow
- private void handleShow() {
- awakenIfNecessary();
- mDialog = createDialog();
- prepareDialog();
- WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();
- attrs.setTitle("GlobalActions");
- mDialog.getWindow().setAttributes(attrs);
- mDialog.show();
- mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);
- }
private void handleShow() {
awakenIfNecessary();
mDialog = createDialog();
prepareDialog();
WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();
attrs.setTitle("GlobalActions");
mDialog.getWindow().setAttributes(attrs);
mDialog.show();
mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);
}
在createDialog中主要是准备Dialog显示的数据,最关键的是mItems, 这代表关机时候显示的每一项,每一项实际是一个action,里面定义了如何创建Diaolg以及点击时的响应,
以添加飞行模式为例,
- // last: silent mode
- if (SHOW_SILENT_TOGGLE) {
- mItems.add(mSilentModeAction);
- }
// last: silent mode
if (SHOW_SILENT_TOGGLE) {
mItems.add(mSilentModeAction);
}
Action接口的实现:
- Implemented By
- GlobalActions.SilentModeTriStateAction
- GlobalActions.SinglePressAction
- GlobalActions.ToggleAction
Implemented By
GlobalActions.SilentModeTriStateAction
GlobalActions.SinglePressAction
GlobalActions.ToggleAction
每一项的动作对应的View添加进MyAdapter,通过ListView来管理
- private MyAdapter mAdapter;
private MyAdapter mAdapter;
在创建Item的时候,
- public View getView(int position, View convertView, ViewGroup parent) {
- Action action = getItem(position);
- return action.create(mContext, convertView, parent, LayoutInflater.from(mContext));
- }
public View getView(int position, View convertView, ViewGroup parent) {
Action action = getItem(position);
return action.create(mContext, convertView, parent, LayoutInflater.from(mContext));
}
会分别调用每一个Action的onCreate来创建每一个Item View,每种Item View对应的实现了Action的接口,从而定义不同的点击动作
以来电模式的选择为例,
createItem:
- public View create(Context context, View convertView, ViewGroup parent,
- LayoutInflater inflater) {
- View v = inflater.inflate(R.layout.global_actions_silent_mode, parent, false);
- int selectedIndex = ringerModeToIndex(mAudioManager.getRingerMode());
- for (int i = 0; i < 3; i++) {
- View itemView = v.findViewById(ITEM_IDS[i]);
- itemView.setSelected(selectedIndex == i);
- // Set up click handler
- itemView.setTag(i);
- itemView.setOnClickListener(this);
- }
- return v;
- }
public View create(Context context, View convertView, ViewGroup parent,
LayoutInflater inflater) {
View v = inflater.inflate(R.layout.global_actions_silent_mode, parent, false);
int selectedIndex = ringerModeToIndex(mAudioManager.getRingerMode());
for (int i = 0; i < 3; i++) {
View itemView = v.findViewById(ITEM_IDS[i]);
itemView.setSelected(selectedIndex == i);
// Set up click handler
itemView.setTag(i);
itemView.setOnClickListener(this);
}
return v;
}
item 响应事件:
- public void onClick(View v) {
- if (!(v.getTag() instanceof Integer)) return;
- int index = (Integer) v.getTag();
- mAudioManager.setRingerMode(indexToRingerMode(index));
- mHandler.sendEmptyMessageDelayed(MESSAGE_DISMISS, DIALOG_DISMISS_DELAY);
- }
public void onClick(View v) {
if (!(v.getTag() instanceof Integer)) return;
int index = (Integer) v.getTag();
mAudioManager.setRingerMode(indexToRingerMode(index));
mHandler.sendEmptyMessageDelayed(MESSAGE_DISMISS, DIALOG_DISMISS_DELAY);
}
当点击了震动后,会调用AudioManager的setRingMode,经过AudioService处理后,会发出RINGER_MODE_CHAGNED_ACTION的广播,然后GlobalActions会接收到广播:
- private BroadcastReceiver mRingerModeReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (intent.getAction().equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
- mHandler.sendEmptyMessage(MESSAGE_REFRESH);
- }
- }
- };
private BroadcastReceiver mRingerModeReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
mHandler.sendEmptyMessage(MESSAGE_REFRESH);
}
}
};
- private Handler mHandler = new Handler() {
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MESSAGE_DISMISS:
- if (mDialog != null) {
- mDialog.dismiss();
- }
- break;
- case MESSAGE_REFRESH:
- refreshSilentMode();
- mAdapter.notifyDataSetChanged();
- break;
- case MESSAGE_SHOW:
- handleShow();
- break;
- }
- }
- };
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_DISMISS:
if (mDialog != null) {
mDialog.dismiss();
}
break;
case MESSAGE_REFRESH:
refreshSilentMode();
mAdapter.notifyDataSetChanged();
break;
case MESSAGE_SHOW:
handleShow();
break;
}
}
};
最终会在Handler中更新图片,然后响应刚才的dismiss事件mHandler.sendEmptyMessageDelayed(MESSAGE_DISMISS, DIALOG_DISMISS_DELAY);让对话框消失
Android通过这样的方式,让程序的扩展性得到了很大的提升,这是值得借鉴的地方