Android长按Power键弹出关机Dialog框GlobalActions解析

Android长按关机键,会弹出关机的对话框,如下图:



现在分析一下详细的流程:

1)  PWM中,会调用

  1. private void interceptPowerKeyDown(boolean handled) {  
  2.     mPowerKeyHandled = handled;  
  3.     if (!handled) {  
  4.         mHandler.postDelayed(mPowerLongPress, ViewConfiguration.getGlobalActionKeyTimeout());  
  5.     }  
  6. }  
    private void interceptPowerKeyDown(boolean handled) {
        mPowerKeyHandled = handled;
        if (!handled) {
            mHandler.postDelayed(mPowerLongPress, ViewConfiguration.getGlobalActionKeyTimeout());
        }
    }
从而进入mPowerLongPress

  1. private final Runnable mPowerLongPress = new Runnable() {  
  2.     @Override  
  3.     public void run() {  
  4.         // The context isn't read  
  5.         if (mLongPressOnPowerBehavior < 0) {  
  6.             mLongPressOnPowerBehavior = mContext.getResources().getInteger(  
  7.                     com.android.internal.R.integer.config_longPressOnPowerBehavior);  
  8.         }  
  9.         ...  
  10.   
  11.         switch (resolvedBehavior) {  
  12.         case LONG_PRESS_POWER_NOTHING:  
  13.             break;  
  14.         case LONG_PRESS_POWER_GLOBAL_ACTIONS:  
  15.             mPowerKeyHandled = true;  
  16.             if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) {  
  17.                 performAuditoryFeedbackForAccessibilityIfNeed();  
  18.             }  
  19.             sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);  
  20.             showGlobalActionsDialog();  
  21.             break;  
  22.             ...  
  23.         }  
  24.     }  
  25. };  
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

  1. void showGlobalActionsDialog() {  
  2.     if (mGlobalActions == null) {  
  3.         mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);  
  4.     }  
  5.     final boolean keyguardShowing = keyguardIsShowingTq();  
  6.     mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());  
  7.     if (keyguardShowing) {  
  8.         // since it took two seconds of long press to bring this up,  
  9.         // poke the wake lock so they have some time to see the dialog.  
  10.         mKeyguardMediator.userActivity();  
  11.     }  
  12. }  
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();
    }
}


分两步来进行,首先创建GlobalActions, 然后在showDialog出来,主要的功能实在showDialog中完成的,

  1. public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {  
  2.     mKeyguardShowing = keyguardShowing;  
  3.     mDeviceProvisioned = isDeviceProvisioned;  
  4.     if (mDialog != null) {  
  5.         mDialog.dismiss();  
  6.         mDialog = null;  
  7.         // Show delayed, so that the dismiss of the previous dialog completes  
  8.         mHandler.sendEmptyMessage(MESSAGE_SHOW);  
  9.     } else {  
  10.         handleShow();  
  11.     }  
  12. }  
    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

  1. private void handleShow() {  
  2.     awakenIfNecessary();  
  3.     mDialog = createDialog();  
  4.     prepareDialog();  
  5.   
  6.     WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();  
  7.     attrs.setTitle("GlobalActions");  
  8.     mDialog.getWindow().setAttributes(attrs);  
  9.     mDialog.show();  
  10.     mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);  
  11. }  
    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以及点击时的响应,

以添加飞行模式为例,

  1. // last: silent mode  
  2. if (SHOW_SILENT_TOGGLE) {  
  3.     mItems.add(mSilentModeAction);  
  4. }  
    // last: silent mode
    if (SHOW_SILENT_TOGGLE) {
        mItems.add(mSilentModeAction);
    }

Action接口的实现:

  1. Implemented By  
  2.   GlobalActions.SilentModeTriStateAction  
  3.   GlobalActions.SinglePressAction  
  4.   GlobalActions.ToggleAction  
  Implemented By
    GlobalActions.SilentModeTriStateAction
    GlobalActions.SinglePressAction
    GlobalActions.ToggleAction

每一项的动作对应的View添加进MyAdapter,通过ListView来管理

  1. private MyAdapter mAdapter;  
private MyAdapter mAdapter;
在创建Item的时候,

  1. public View getView(int position, View convertView, ViewGroup parent) {  
  2.     Action action = getItem(position);  
  3.     return action.create(mContext, convertView, parent, LayoutInflater.from(mContext));  
  4. }  
    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:

  1. public View create(Context context, View convertView, ViewGroup parent,  
  2.         LayoutInflater inflater) {  
  3.     View v = inflater.inflate(R.layout.global_actions_silent_mode, parent, false);  
  4.   
  5.     int selectedIndex = ringerModeToIndex(mAudioManager.getRingerMode());  
  6.     for (int i = 0; i < 3; i++) {  
  7.         View itemView = v.findViewById(ITEM_IDS[i]);  
  8.         itemView.setSelected(selectedIndex == i);  
  9.         // Set up click handler  
  10.         itemView.setTag(i);  
  11.         itemView.setOnClickListener(this);  
  12.     }  
  13.     return v;  
  14. }  
        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 响应事件:

  1. public void onClick(View v) {  
  2.     if (!(v.getTag() instanceof Integer)) return;  
  3.   
  4.     int index = (Integer) v.getTag();  
  5.     mAudioManager.setRingerMode(indexToRingerMode(index));  
  6.     mHandler.sendEmptyMessageDelayed(MESSAGE_DISMISS, DIALOG_DISMISS_DELAY);  
  7. }  
    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会接收到广播:

  1. private BroadcastReceiver mRingerModeReceiver = new BroadcastReceiver() {  
  2.     @Override  
  3.     public void onReceive(Context context, Intent intent) {  
  4.         if (intent.getAction().equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {  
  5.             mHandler.sendEmptyMessage(MESSAGE_REFRESH);  
  6.         }  
  7.     }  
  8. };  
    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);
            }
        }
    };

  1. private Handler mHandler = new Handler() {  
  2.         public void handleMessage(Message msg) {  
  3.             switch (msg.what) {  
  4.             case MESSAGE_DISMISS:  
  5.                 if (mDialog != null) {  
  6.                     mDialog.dismiss();  
  7.                 }  
  8.                 break;  
  9.             case MESSAGE_REFRESH:  
  10.                 refreshSilentMode();  
  11.                 mAdapter.notifyDataSetChanged();  
  12.                 break;  
  13.             case MESSAGE_SHOW:  
  14.                 handleShow();  
  15.                 break;  
  16.             }  
  17.         }  
  18.     };  
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通过这样的方式,让程序的扩展性得到了很大的提升,这是值得借鉴的地方

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值