亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

Audio系列之音量鍵

2019-11-09 18:59:34
字體:
來源:轉載
供稿:網友

根據按鍵派發策略,派發順序是Activity,然后是PhoneWindow。

如果activity需要處理音量鍵,可以在應用中重寫Activity 的onKeyDown()方法以截獲音量鍵將其用作其他功能,如相機的音量快捷鍵。Activity#onKeyDown()方法源碼

/**     * Called when a key was PRessed down and not handled by any of the views     * inside of the activity. So, for example, key presses while the cursor     * is inside a TextView will not trigger the event (unless it is a navigation     * to another object) because TextView handles its own key presses.     *     * <p>If the focused view didn't want this event, this method is called.     *     * <p>The default implementation takes care of {@link KeyEvent#KEYCODE_BACK}     * by calling {@link #onBackPressed()}, though the behavior varies based     * on the application compatibility mode: for     * {@link android.os.Build.VERSION_CODES#ECLAIR} or later applications,     * it will set up the dispatch to call {@link #onKeyUp} where the action     * will be performed; for earlier applications, it will perform the     * action immediately in on-down, as those versions of the platform     * behaved.     *     * <p>Other additional default key handling may be performed     * if configured with {@link #setDefaultKeyMode}.     *     * @return Return <code>true</code> to prevent this event from being propagated     * further, or <code>false</code> to indicate that you have not handled     * this event and it should continue to be propagated.     * @see #onKeyUp     * @see android.view.KeyEvent     */    public boolean onKeyDown(int keyCode, KeyEvent event)  {        if (keyCode == KeyEvent.KEYCODE_BACK) {            if (getApplicationInfo().targetSdkVersion                    >= Build.VERSION_CODES.ECLAIR) {                event.startTracking();            } else {                onBackPressed();            }            return true;        }        if (mDefaultKeyMode == DEFAULT_KEYS_DISABLE) {            return false;        } else if (mDefaultKeyMode == DEFAULT_KEYS_SHORTCUT) {            Window w = getWindow();            if (w.hasFeature(Window.FEATURE_OPTIONS_PANEL) &&                    w.performPanelShortcut(Window.FEATURE_OPTIONS_PANEL, keyCode, event,                            Menu.FLAG_ALWAYS_PERFORM_CLOSE)) {                return true;            }            return false;        } else {            // Common code for DEFAULT_KEYS_DIALER & DEFAULT_KEYS_SEARCH_*            boolean clearSpannable = false;            boolean handled;            if ((event.getRepeatCount() != 0) || event.isSystem()) {                clearSpannable = true;                handled = false;            } else {                handled = TextKeyListener.getInstance().onKeyDown(                        null, mDefaultKeySsb, keyCode, event);                if (handled && mDefaultKeySsb.length() > 0) {                    // something useable has been typed - dispatch it now.                    final String str = mDefaultKeySsb.toString();                    clearSpannable = true;                    switch (mDefaultKeyMode) {                    case DEFAULT_KEYS_DIALER:                        Intent intent = new Intent(Intent.ACTION_DIAL,  Uri.parse("tel:" + str));                        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);                        startActivity(intent);                        break;                    case DEFAULT_KEYS_SEARCH_LOCAL:                        startSearch(str, false, null, false);                        break;                    case DEFAULT_KEYS_SEARCH_GLOBAL:                        startSearch(str, false, null, true);                        break;                    }                }            }            if (clearSpannable) {                mDefaultKeySsb.clear();                mDefaultKeySsb.clearSpans();                Selection.setSelection(mDefaultKeySsb,0);            }            return handled;        }    }

Activity.onKeyDown()對一般按鍵有默認的一些處理,但是我們可以復寫這個方法以處理我們想要處理的按鍵。如果不做處理,會讓PhoneWindow的onKeyDown處理,下面是PhoneWindow#onKeyDown()方法源碼:

protected boolean onKeyDown(int featureId, int keyCode, KeyEvent event) {        /* ****************************************************************************         * HOW TO DECIDE WHERE YOUR KEY HANDLING GOES.         *         * If your key handling must happen before the app gets a crack at the event,         * it goes in PhoneWindowManager.         *         * If your key handling should happen in all windows, and does not depend on         * the state of the current application, other than that the current         * application can override the behavior by handling the event itself, it         * should go in PhoneFallbackEventHandler.         *         * Only if your handling depends on the window, and the fact that it has         * a DecorView, should it go here.         * ****************************************************************************/        final KeyEvent.DispatcherState dispatcher =                mDecor != null ? mDecor.getKeyDispatcherState() : null;        //Log.i(TAG, "Key down: repeat=" + event.getRepeatCount()        //        + " flags=0x" + Integer.toHexString(event.getFlags()));        switch (keyCode) {            case KeyEvent.KEYCODE_VOLUME_UP:            case KeyEvent.KEYCODE_VOLUME_DOWN:            case KeyEvent.KEYCODE_VOLUME_MUTE: {                int direction = 0;                switch (keyCode) {                    case KeyEvent.KEYCODE_VOLUME_UP:                        direction = AudioManager.ADJUST_RAISE;                        break;                    case KeyEvent.KEYCODE_VOLUME_DOWN:                        direction = AudioManager.ADJUST_LOWER;                        break;                    case KeyEvent.KEYCODE_VOLUME_MUTE:                        direction = AudioManager.ADJUST_TOGGLE_MUTE;                        break;                }                // If we have a session send it the volume command, otherwise                // use the suggested stream.                if (mMediaController != null) {                    mMediaController.adjustVolume(direction, AudioManager.FLAG_SHOW_UI);                } else {                    MediaSessionLegacyHelper.getHelper(getContext()).sendAdjustVolumeBy(                            mVolumeControlStreamType, direction,                            AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE                                    | AudioManager.FLAG_FROM_KEY);                }                return true;            }            // These are all the recognized media key codes in            // KeyEvent.isMediaKey()            case KeyEvent.KEYCODE_MEDIA_PLAY:            case KeyEvent.KEYCODE_MEDIA_PAUSE:            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:            case KeyEvent.KEYCODE_MUTE:            case KeyEvent.KEYCODE_HEADSETHOOK:            case KeyEvent.KEYCODE_MEDIA_STOP:            case KeyEvent.KEYCODE_MEDIA_NEXT:            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:            case KeyEvent.KEYCODE_MEDIA_REWIND:            case KeyEvent.KEYCODE_MEDIA_RECORD:            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {                if (mMediaController != null) {                    if (mMediaController.dispatchMediaButtonEvent(event)) {                        return true;                    }                }                return false;            }            case KeyEvent.KEYCODE_MENU: {                onKeyDownPanel((featureId < 0) ? FEATURE_OPTIONS_PANEL : featureId, event);                return true;            }            case KeyEvent.KEYCODE_BACK: {                if (event.getRepeatCount() > 0) break;                if (featureId < 0) break;                // Currently don't do anything with long press.                if (dispatcher != null) {                    dispatcher.startTracking(event, this);                }                return true;            }        }        return false;    }在PhoneWindow#onKeyDown()中最終調用mMediaController.adjustVolume(direction, AudioManager.FLAG_SHOW_UI);調節音量,源碼如下:

/**     * Adjust the volume of the output this session is playing on. The direction     * must be one of {@link AudioManager#ADJUST_LOWER},     * {@link AudioManager#ADJUST_RAISE}, or {@link AudioManager#ADJUST_SAME}.     * The command will be ignored if the session does not support     * {@link VolumeProvider#VOLUME_CONTROL_RELATIVE} or     * {@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}. The flags in     * {@link AudioManager} may be used to affect the handling.     *     * @see #getPlaybackInfo()     * @param direction The direction to adjust the volume in.     * @param flags Any flags to pass with the command.     */    public void adjustVolume(int direction, int flags) {        try {            mSessionBinder.adjustVolume(direction, flags, mContext.getPackageName());        } catch (RemoteException e) {            Log.wtf(TAG, "Error calling adjustVolumeBy.", e);        }    }在PhoneWindow#onKeyDown()的flag有幾個,其中AudioManager.FLAG_SHOW_UI告訴AudioService需要彈出一個音量控制板。而PhoneWindow#onKeyUp()中對應的有AudioManager.FLAG_PLAY_SOUND,這是告訴AudioService松開音量鍵后有提示音,還有更多的flag自己去看。

每個流類型(StreamType)都有獨立的音量值。而PhoneWindow最終設置的音量所屬類型由PhoneWindow#mVolumeControlStream決定,在Activity#setVolumeControlStream()可以設置綁定的PhoneWindow的mVolumeControlStream。

音量按鍵有三個值,分別是KeyEvent.KEYCODE_VOLUME_UP(加), KeyEvent.KEYCODE_VOLUME_DOWN(減), KeyEvent.KEYCODE_VOLUME_MUTE(靜音)

音量改變后,會發廣播,下面是AudioService#setIndex()源碼:

mVolumeChanged = new Intent(AudioManager.VOLUME_CHANGED_ACTION);mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);                mVolumeChanged.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);                mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE_ALIAS,                        mStreamVolumeAlias[mStreamType]);                sendBroadcastToAll(mVolumeChanged);


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲精品不卡在线| 福利一区视频在线观看| 日韩成人在线免费观看| 亚洲激情视频网| 国产精品一区电影| 色爱av美腿丝袜综合粉嫩av| 伊人久久久久久久久久久| 日韩日本欧美亚洲| 欧美极品少妇全裸体| 亚洲天堂av在线免费| 久久激情视频久久| 亚洲一区二区久久久久久久| 国产一区二区三区中文| 97视频免费在线看| 色综合导航网站| 成人av.网址在线网站| 日本久久中文字幕| 色香阁99久久精品久久久| 亚洲欧美视频在线| 国产999精品久久久影片官网| 成人黄色av网| 欧美色另类天堂2015| 国产精品情侣自拍| 中国china体内裑精亚洲片| 欧美激情第三页| 亚洲免费精彩视频| 搡老女人一区二区三区视频tv| 亚洲在线免费观看| 久久99热精品这里久久精品| 国产91成人video| 91亚洲精品久久久| 日韩中文字幕国产精品| 久久青草福利网站| 久久人体大胆视频| 欧美日韩日本国产| 久久综合伊人77777尤物| 超碰97人人做人人爱少妇| 久久99国产精品久久久久久久久| 美日韩丰满少妇在线观看| 亚洲三级免费看| 伊人亚洲福利一区二区三区| 日韩成人高清在线| 亚洲美女在线看| 亚洲性xxxx| 国产这里只有精品| 久久久久久高潮国产精品视| 欧美电影免费观看大全| 欧美激情欧美激情| 国产欧美一区二区三区四区| 岛国av在线不卡| 日韩专区中文字幕| 午夜精品一区二区三区视频免费看| 国产精品视频免费在线| 久久综合伊人77777尤物| 亚洲欧美国产高清va在线播| 91在线免费看网站| 国产精品久久77777| 亚洲人成电影在线观看天堂色| 97在线观看视频| 91精品视频观看| 美女视频久久黄| 91九色国产社区在线观看| 国产欧美一区二区三区久久| 亚州欧美日韩中文视频| 综合激情国产一区| 国产亚洲日本欧美韩国| 欧美大尺度电影在线观看| 国产成人av网| 国产一区二区欧美日韩| 久久亚洲精品成人| 日韩在线中文字| 日韩亚洲欧美中文在线| 日韩在线观看成人| 成人有码在线播放| 日韩中文在线视频| 日韩av免费一区| 成人性生交大片免费观看嘿嘿视频| 亚洲成人中文字幕| 久久久久久久久久国产精品| 亚洲国内精品在线| 久久久成人精品视频| 亚洲欧美国产一区二区三区| 国产精品视频一区二区三区四| 欧美性生交大片免网| 久久久久久久久久久av| 久久成人亚洲精品| 亚洲人成网站777色婷婷| 国产狼人综合免费视频| 国产精品成av人在线视午夜片| 亚洲丁香久久久| 亚洲欧美色图片| 国产精自产拍久久久久久| 国产精品福利在线| 中文字幕精品一区久久久久| 亚洲人成网站777色婷婷| 欧美精品18videos性欧| 成人乱色短篇合集| 97免费在线视频| 欧洲s码亚洲m码精品一区| 国产精品欧美日韩一区二区| 久久亚洲精品毛片| 97在线视频一区| 午夜精品久久久久久久99热| 欧美激情欧美激情在线五月| 欧美精品在线免费观看| 欧美大片免费看| 91成人在线视频| 久久噜噜噜精品国产亚洲综合| 久久久久99精品久久久久| 日韩av大片在线| 一个色综合导航| 国产成人激情视频| 草民午夜欧美限制a级福利片| 欧美另类交人妖| 亚洲视频在线视频| 精品一区电影国产| 欧美xxxx做受欧美.88| 国产精品第一区| 久久久精品免费视频| 91精品美女在线| 777777777亚洲妇女| 亚洲色图日韩av| 久久久久久久久国产精品| 国产精品99导航| 亚洲激情国产精品| 色综合天天综合网国产成人网| 亚洲国产精彩中文乱码av在线播放| 国产成人综合精品| 色与欲影视天天看综合网| 91在线色戒在线| 亚洲二区在线播放视频| 人人澡人人澡人人看欧美| 91久久精品日日躁夜夜躁国产| 亚洲第一区中文99精品| 日韩av中文字幕在线播放| 亚洲国产一区二区三区在线观看| 色噜噜国产精品视频一区二区| 国产精品亚洲片夜色在线| 国产欧美日韩免费| 欧美极品在线视频| 亚洲欧美精品中文字幕在线| 欧美猛男性生活免费| 欧美大尺度激情区在线播放| 日韩中文字幕在线精品| 久久久亚洲成人| 成人午夜在线影院| 国产国语刺激对白av不卡| 久久免费精品日本久久中文字幕| 欧美激情一级精品国产| 96sao精品视频在线观看| 久久久精品一区二区三区| 国产亚洲欧美日韩一区二区| 国产成人精品久久久| 久久久亚洲福利精品午夜| 不卡中文字幕av| 色偷偷偷亚洲综合网另类| 欧美午夜片在线免费观看| 国产成人高清激情视频在线观看| 精品亚洲一区二区三区四区五区| 国产精品va在线| 一区二区三区四区在线观看视频| 日韩精品中文字幕在线观看| 亚洲精品免费在线视频| 国产一区二区丝袜|