import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
+import android.telephony.TelephonyManager;
import android.util.AndroidRuntimeException;
import android.util.Config;
import android.util.EventLog;
private ContextMenuBuilder mContextMenu;
private MenuDialogHelper mContextMenuHelper;
-
+
private int mVolumeControlStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE;
private long mVolumeKeyUpTime;
private KeyguardManager mKeyguardManager = null;
+
+ private TelephonyManager mTelephonyManager = null;
private boolean mSearchKeyDownReceived;
-
+
private boolean mKeycodeCallTimeoutActive = false;
private boolean mKeycodeCameraTimeoutActive = false;
static final int MSG_CALL_LONG_PRESS_COMPLETE = 4;
static final int MSG_CAMERA_LONG_PRESS = 5;
static final int MSG_CAMERA_LONG_PRESS_COMPLETE = 6;
-
+
private final Handler mKeycodeMenuTimeoutHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
case MSG_CAMERA_LONG_PRESS: {
if (!mKeycodeCameraTimeoutActive) return;
// See above.
- mKeycodeMenuTimeoutHandler.sendEmptyMessage(
- MSG_CAMERA_LONG_PRESS_COMPLETE);
+ Message newMessage = Message.obtain(msg);
+ newMessage.what = MSG_CAMERA_LONG_PRESS_COMPLETE;
+ mKeycodeMenuTimeoutHandler.sendMessage(newMessage);
break;
}
case MSG_MENU_LONG_PRESS_COMPLETE: {
}
}
};
-
+
public PhoneWindow(Context context) {
super(context);
mLayoutInflater = LayoutInflater.from(context);
if (cb != null) {
st.createdPanelView = cb.onCreatePanelView(st.featureId);
}
-
+
if (st.createdPanelView == null) {
// Init the panel state's menu--return false if init failed
if (st.menu == null) {
if ((cb == null) || !cb.onCreatePanelMenu(st.featureId, st.menu)) {
// Ditch the menu created above
st.menu = null;
-
+
return false;
}
}
-
+
// Callback and return if the callback does not want to show the menu
if (!cb.onPreparePanel(st.featureId, st.createdPanelView, st.menu)) {
return false;
}
-
+
// Set the proper keymap
KeyCharacterMap kmap = KeyCharacterMap.load(event != null ? event.getDeviceId() : 0);
st.qwertyMode = kmap.getKeyboardType() != KeyCharacterMap.NUMERIC;
PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
if ((st != null) && (st.menu != null)) {
final MenuBuilder menuBuilder = (MenuBuilder) st.menu;
-
+
if (st.isOpen) {
// Freeze state
final Bundle state = new Bundle();
// Remove the menu views since they need to be recreated
// according to the new configuration
clearMenuViews(st);
-
+
// Re-open the same menu
reopenMenu(false);
clearMenuViews(st);
}
}
-
+
}
private static void clearMenuViews(PanelFeatureState st) {
// This can be called on config changes, so we should make sure
// the views will be reconstructed based on the new orientation, etc.
-
+
// Allow the callback to create a new panel view
st.createdPanelView = null;
-
- // Causes the decor view to be recreated
+
+ // Causes the decor view to be recreated
st.refreshDecorView = true;
-
+
((MenuBuilder) st.menu).clearMenuViews();
}
-
+
@Override
public final void openPanel(int featureId, KeyEvent event) {
openPanel(getPanelState(featureId, true), event);
closePanel(st, true);
return;
}
-
+
final WindowManager wm = getWindowManager();
if (wm == null) {
return;
lp = new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
}
- int backgroundResId;
+ int backgroundResId;
if (lp.width == ViewGroup.LayoutParams.FILL_PARENT) {
// If the contents is fill parent for the width, set the
// corresponding background
}
st.decorView.setWindowBackground(getContext().getResources().getDrawable(
backgroundResId));
-
+
st.decorView.addView(st.shownPanelView, lp);
-
+
/*
* Give focus to the view, if it or one of its children does not
* already have it.
// This view is no longer shown, so null it out
st.shownPanelView = null;
-
+
if (st.isInExpandedMode) {
// Next time the menu opens, it should not be in expanded mode, so
// force a refresh of the decor
if (mPanelChordingKey != 0) {
mPanelChordingKey = 0;
mKeycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS);
-
+
boolean playSoundEffect = false;
PanelFeatureState st = getPanelState(featureId, true);
if (st.isOpen || st.isHandled) {
-
+
// Play the sound effect if the user closed an open menu (and not if
// they just released a menu shortcut)
playSoundEffect = st.isOpen;
-
+
// Close menu
closePanel(st, true);
-
+
} else if (st.isPrepared) {
-
+
// Write 'menu opened' to event log
EventLog.writeEvent(50001, 0);
-
+
// Show menu
openPanel(st, event);
-
+
playSoundEffect = true;
}
-
+
if (playSoundEffect) {
AudioManager audioManager = (AudioManager) getContext().getSystemService(
Context.AUDIO_SERVICE);
*/
private synchronized void dismissContextMenu() {
mContextMenu = null;
-
+
if (mContextMenuHelper != null) {
mContextMenuHelper.dismiss();
mContextMenuHelper = null;
* @return Whether the initialization was successful.
*/
protected boolean initializePanelContent(PanelFeatureState st) {
-
+
if (st.createdPanelView != null) {
st.shownPanelView = st.createdPanelView;
return true;
}
-
+
final MenuBuilder menu = (MenuBuilder)st.menu;
if (menu == null) {
return false;
return true;
}
+
+ case KeyEvent.KEYCODE_PLAYPAUSE:
+ /* Suppress PLAYPAUSE toggle when phone is ringing or in-call
+ * to avoid music playback */
+ if (mTelephonyManager == null) {
+ mTelephonyManager = (TelephonyManager) getContext().getSystemService(
+ Context.TELEPHONY_SERVICE);
+ }
+ if (mTelephonyManager != null &&
+ mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE) {
+ return true; // suppress key event
+ }
case KeyEvent.KEYCODE_MUTE:
case KeyEvent.KEYCODE_HEADSETHOOK:
- case KeyEvent.KEYCODE_PLAYPAUSE:
case KeyEvent.KEYCODE_STOP:
case KeyEvent.KEYCODE_NEXTSONG:
case KeyEvent.KEYCODE_PREVIOUSSONG:
ViewConfiguration.getLongPressTimeout());
return true;
}
-
+
case KeyEvent.KEYCODE_SEARCH: {
if (event.getRepeatCount() == 0) {
mSearchKeyDownReceived = true;
return true;
}
- case KeyEvent.KEYCODE_HEADSETHOOK:
- case KeyEvent.KEYCODE_PLAYPAUSE:
- case KeyEvent.KEYCODE_STOP:
- case KeyEvent.KEYCODE_NEXTSONG:
- case KeyEvent.KEYCODE_PREVIOUSSONG:
- case KeyEvent.KEYCODE_REWIND:
+ case KeyEvent.KEYCODE_HEADSETHOOK:
+ case KeyEvent.KEYCODE_PLAYPAUSE:
+ case KeyEvent.KEYCODE_STOP:
+ case KeyEvent.KEYCODE_NEXTSONG:
+ case KeyEvent.KEYCODE_PREVIOUSSONG:
+ case KeyEvent.KEYCODE_REWIND:
case KeyEvent.KEYCODE_FORWARD: {
Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
// The panel must not have been required, and is currently not around, skip it
continue;
}
-
+
st.onRestoreInstanceState(icicles.get(curFeatureId));
}
mVolumeControlStreamType, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
}
}
-
+
if (isDown && (event.getRepeatCount() == 0)) {
// First handle chording of panel key: if a panel key is held
// but not released, try to execute a shortcut in it.
// prepared panel or menu).
boolean handled = performPanelShortcut(mPreparedPanel, keyCode, event,
Menu.FLAG_PERFORM_NO_CLOSE);
-
+
if (!handled) {
/*
* If not handled, then pass it to the view hierarchy
return isDown ? PhoneWindow.this.onKeyDown(mFeatureId, event.getKeyCode(), event)
: PhoneWindow.this.onKeyUp(mFeatureId, event.getKeyCode(), event);
}
-
+
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
final Callback cb = getCallback();
}
}
-
+
@Override
public boolean showContextMenuForChild(View originalView) {
// Reuse the context menu builder
drawableChanged();
}
}
-
+
@Override
protected boolean fitSystemWindows(Rect insets) {
mFrameOffsets.set(insets);
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
-
+
// no KEYCODE_CALL events active across focus changes
mKeycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS);
mKeycodeMenuTimeoutHandler.removeMessages(MSG_CALL_LONG_PRESS);
if (!hasWindowFocus && mPanelChordingKey > 0) {
closePanel(FEATURE_OPTIONS_PANEL);
}
-
+
final Callback cb = getCallback();
if (cb != null && mFeatureId < 0) {
cb.onWindowFocusChanged(hasWindowFocus);
} else {
setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate);
}
-
+
if (a.getBoolean(com.android.internal.R.styleable.Window_windowNoTitle, false)) {
requestFeature(FEATURE_NO_TITLE);
}
}
WindowManager.LayoutParams params = getAttributes();
-
+
if (!hasSoftInputMode()) {
params.softInputMode = a.getInt(
com.android.internal.R.styleable.Window_windowSoftInputMode,
params.softInputMode);
}
-
+
if (a.getBoolean(com.android.internal.R.styleable.Window_backgroundDimEnabled,
mIsFloating)) {
/* All dialogs should have the window dimmed */
params.windowAnimations = a.getResourceId(
com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
}
-
+
// The rest are only done if this window is not embedded; otherwise,
// the values are inherited from our container.
if (getContainer() == null) {
/**
* Gets a panel's state based on its feature ID.
- *
+ *
* @param featureId The feature ID of the panel.
* @param required Whether the panel is required (if it is required and it
* isn't in our features, this throws an exception).
private PanelFeatureState getPanelState(int featureId, boolean required) {
return getPanelState(featureId, required, null);
}
-
+
/**
* Gets a panel's state based on its feature ID.
- *
+ *
* @param featureId The feature ID of the panel.
* @param required Whether the panel is required (if it is required and it
* isn't in our features, this throws an exception).
}
private void updateInt(int featureId, int value, boolean fromResume) {
-
+
// Do nothing if the decor is not yet installed... an update will
// need to be forced when we eventually become active.
if (mContentParent == null) {
* callback. This method will grab whatever extra state is needed for the
* callback that isn't given in the parameters. If the panel is not open,
* this will not perform the callback.
- *
+ *
* @param featureId Feature ID of the panel that was closed. Must be given.
* @param panel Panel that was closed. Optional but useful if there is no
* menu given.
/**
* Helper method for adding launch-search to most applications. Opens the
* search window using default settings.
- *
+ *
* @return true if search window opened
*/
private boolean launchDefaultSearch() {
return cb.onSearchRequested();
}
}
-
+
@Override
public void setVolumeControlStream(int streamType) {
mVolumeControlStreamType = streamType;
}
private static final class PanelFeatureState {
-
+
/** Feature ID for this panel. */
int featureId;
/** The panel that was returned by onCreatePanelView(). */
View createdPanelView;
-
+
/** The panel that we are actually showing. */
View shownPanelView;
- /** Use {@link #setMenu} to set this. */
+ /** Use {@link #setMenu} to set this. */
Menu menu;
/**
* Contains the state of the menu when told to freeze.
*/
Bundle frozenMenuState;
-
+
PanelFeatureState(int featureId) {
this.featureId = featureId;
void setMenu(Menu menu) {
this.menu = menu;
-
+
if (frozenMenuState != null) {
((MenuBuilder) menu).restoreHierarchyState(frozenMenuState);
frozenMenuState = null;
savedState.menuState = new Bundle();
((MenuBuilder) menu).saveHierarchyState(savedState.menuState);
}
-
+
return savedState;
}
shownPanelView = null;
decorView = null;
}
-
+
private static class SavedState implements Parcelable {
int featureId;
boolean isOpen;
boolean isInExpandedMode;
Bundle menuState;
-
+
public int describeContents() {
return 0;
}
dest.writeBundle(menuState);
}
}
-
+
private static SavedState readFromParcel(Parcel source) {
SavedState savedState = new SavedState();
savedState.featureId = source.readInt();
savedState.isOpen = source.readInt() == 1;
savedState.isInExpandedMode = source.readInt() == 1;
-
+
if (savedState.isOpen) {
savedState.menuState = source.readBundle();
}
-
+
return savedState;
}
-
+
public static final Parcelable.Creator<SavedState> CREATOR
= new Parcelable.Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
}
};
}
-
+
}
/**
private final class ContextMenuCallback implements MenuBuilder.Callback {
private int mFeatureId;
private MenuDialogHelper mSubMenuHelper;
-
+
public ContextMenuCallback(int featureId) {
mFeatureId = featureId;
}
if (allMenusAreClosing) {
Callback callback = getCallback();
if (callback != null) callback.onPanelClosed(mFeatureId, menu);
-
+
if (menu == mContextMenu) {
dismissContextMenu();
}
-
+
// Dismiss the submenu, if it is showing
if (mSubMenuHelper != null) {
mSubMenuHelper.dismiss();
// The window manager will give us a valid window token
mSubMenuHelper = new MenuDialogHelper(subMenu);
mSubMenuHelper.show(null);
-
+
return true;
}
}