+++ /dev/null
-#
-# Copyright (C) 2008 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-# Make sure our needed product policy is present.
-ifeq ($(PRODUCT_POLICY),)
-$(error PRODUCT_POLICY MUST be defined.)
-else
- ifeq ($(filter $(PRODUCT_POLICY),$(ALL_MODULES)),)
- $(error No module defined for the given PRODUCT_POLICY ($(PRODUCT_POLICY)))
- else
- # The policy MUST specify a module which builds a single jar
- ifneq ($(words $(call module-built-files,$(PRODUCT_POLICY))),1)
- $(error Policy module $(PRODUCT_POLICY) must build a single library jar)
- endif
- endif
-endif
-
-
-# We will always build all the policies. Then, we will copy the jars from
-# the product specified policy into the locations where the current module
-# is expected to have its jars. Then, the normal module install code will
-# take care of things. We make each policy me non-installable, so that only
-# the right one gets taken and installed. Having all the policies built
-# also allows us to have unittests that refer to specific policies, but not
-# necessarily the one used for the current product being built.
-# TODO: Is this the best way to do this?
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := android.policy
-LOCAL_MODULE_CLASS := JAVA_LIBRARIES
-LOCAL_MODULE_SUFFIX := $(COMMON_JAVA_PACKAGE_SUFFIX)
-
-LOCAL_BUILT_MODULE_STEM := javalib.jar
-
-# base_rules.mk may use this in unintended ways if a stale value is
-# left lying around, so make sure to clear it.
-all_res_assets :=
-
-#######################################
-include $(BUILD_SYSTEM)/base_rules.mk
-#######################################
-
-src_classes_jar := $(call _java-lib-full-classes.jar,$(PRODUCT_POLICY))
-tgt_classes_jar := $(call _java-lib-full-classes.jar,$(LOCAL_MODULE))
-
-src_javalib_jar := $(call module-built-files,$(PRODUCT_POLICY))
-tgt_javalib_jar := $(LOCAL_BUILT_MODULE)
-
-# make sure that the classes file gets there first since some rules in other
-# places assume that the classes.jar for a module exists if the javalib.jar
-# file exists.
-$(tgt_javalib_jar): $(tgt_classes_jar)
-
-$(tgt_javalib_jar): $(src_javalib_jar) | $(ACP)
- @echo "Copying policy javalib.jar: $@"
- $(copy-file-to-target)
-
-$(tgt_classes_jar): $(src_classes_jar) | $(ACP)
- @echo "Copying policy classes.jar: $@"
- $(copy-file-to-target)
-
-#
-# Clean up after ourselves when switching build types
-#
-.PHONY: policy_installclean
-policy_installclean: PRIVATE_CLEAN_DIR := $(call local-intermediates-dir,COMMON)
-policy_installclean:
- $(hide) rm -rf $(PRIVATE_CLEAN_DIR)
-
-installclean: policy_installclean
+++ /dev/null
-LOCAL_PATH:= $(call my-dir)
-
-# the library
-# ============================================================
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
- $(call all-subdir-java-files)
-
-LOCAL_MODULE := android.policy_mid
-LOCAL_UNINSTALLABLE_MODULE := true
-
-include $(BUILD_JAVA_LIBRARY)
+++ /dev/null
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import com.android.internal.R;
-import com.google.android.collect.Lists;
-
-import android.app.AlertDialog;
-import android.app.StatusBarManager;
-import android.content.Context;
-import android.content.BroadcastReceiver;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.DialogInterface;
-import android.media.AudioManager;
-import android.os.LocalPowerManager;
-import android.os.Handler;
-import android.os.Message;
-import android.os.SystemClock;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.BaseAdapter;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import java.util.ArrayList;
-
-/**
- * Helper to show the global actions dialog. Each item is an {@link Action} that
- * may show depending on whether the keyguard is showing, and whether the device
- * is provisioned.
- */
-class GlobalActions implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener {
-
- private StatusBarManager mStatusBar;
-
- private final Context mContext;
- private final LocalPowerManager mPowerManager;
- private final AudioManager mAudioManager;
- private ArrayList<Action> mItems;
- private AlertDialog mDialog;
-
- private ToggleAction mSilentModeToggle;
-
- private MyAdapter mAdapter;
-
- private boolean mKeyguardShowing = false;
- private boolean mDeviceProvisioned = false;
-
- /**
- * @param context everything needs a context :)
- * @param powerManager used to turn the screen off (the lock action).
- */
- public GlobalActions(Context context, LocalPowerManager powerManager) {
- mContext = context;
- mPowerManager = powerManager;
- mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
-
- // receive broadcasts
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
- context.registerReceiver(mBroadcastReceiver, filter);
- }
-
- /**
- * Show the global actions dialog (creating if necessary)
- * @param keyguardShowing True if keyguard is showing
- */
- public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {
- mKeyguardShowing = keyguardShowing;
- mDeviceProvisioned = isDeviceProvisioned;
- if (mDialog == null) {
- mStatusBar = (StatusBarManager)mContext.getSystemService(Context.STATUS_BAR_SERVICE);
- mDialog = createDialog();
- }
- prepareDialog();
-
- mStatusBar.disable(StatusBarManager.DISABLE_EXPAND);
- mDialog.show();
- }
-
- /**
- * Create the global actions dialog.
- * @return A new dialog.
- */
- private AlertDialog createDialog() {
-
- mSilentModeToggle = new ToggleAction(
- R.drawable.ic_lock_silent_mode,
- R.drawable.ic_lock_silent_mode_off,
- R.string.global_action_toggle_silent_mode,
- R.string.global_action_silent_mode_on_status,
- R.string.global_action_silent_mode_off_status) {
-
- void onToggle(boolean on) {
- mAudioManager.setRingerMode(on ? AudioManager.RINGER_MODE_SILENT
- : AudioManager.RINGER_MODE_NORMAL);
- }
-
- public boolean showDuringKeyguard() {
- return true;
- }
-
- public boolean showBeforeProvisioning() {
- return false;
- }
- };
-
- mItems = Lists.newArrayList(
- // first: lock screen
- new SinglePressAction(com.android.internal.R.drawable.ic_lock_lock, R.string.global_action_lock) {
-
- public void onPress() {
- mPowerManager.goToSleep(SystemClock.uptimeMillis() + 1);
- }
-
- public boolean showDuringKeyguard() {
- return false;
- }
-
- public boolean showBeforeProvisioning() {
- return false;
- }
- },
- // next: silent mode
- mSilentModeToggle,
- // last: power off
- new SinglePressAction(com.android.internal.R.drawable.ic_lock_power_off, R.string.global_action_power_off) {
-
- public void onPress() {
- // shutdown by making sure radio and power are handled accordingly.
- ShutdownThread.shutdownAfterDisablingRadio(mContext, true);
- }
-
- public boolean showDuringKeyguard() {
- return true;
- }
-
- public boolean showBeforeProvisioning() {
- return true;
- }
- });
-
- mAdapter = new MyAdapter();
-
- final AlertDialog.Builder ab = new AlertDialog.Builder(mContext);
-
- ab.setAdapter(mAdapter, this)
- .setInverseBackgroundForced(true)
- .setTitle(R.string.global_actions);
-
- final AlertDialog dialog = ab.create();
- dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
- dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
- WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
-
- dialog.setOnDismissListener(this);
-
- return dialog;
- }
-
- private void prepareDialog() {
- // TODO: May need another 'Vibrate' toggle button, but for now treat them the same
- final boolean silentModeOn =
- mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL;
- mSilentModeToggle.updateState(silentModeOn);
- mAdapter.notifyDataSetChanged();
- if (mKeyguardShowing) {
- mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
- } else {
- mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
- }
- }
-
- /** {@inheritDoc} */
- public void onDismiss(DialogInterface dialog) {
- mStatusBar.disable(StatusBarManager.DISABLE_NONE);
- }
-
- /** {@inheritDoc} */
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- mAdapter.getItem(which).onPress();
- }
-
-
- /**
- * The adapter used for the list within the global actions dialog, taking
- * into account whether the keyguard is showing via
- * {@link GlobalActions#mKeyguardShowing} and whether the device is provisioned
- * via {@link GlobalActions#mDeviceProvisioned}.
- */
- private class MyAdapter extends BaseAdapter {
-
- public int getCount() {
- int count = 0;
-
- for (int i = 0; i < mItems.size(); i++) {
- final Action action = mItems.get(i);
-
- if (mKeyguardShowing && !action.showDuringKeyguard()) {
- continue;
- }
- if (!mDeviceProvisioned && !action.showBeforeProvisioning()) {
- continue;
- }
- count++;
- }
- return count;
- }
-
- public Action getItem(int position) {
-
- int filteredPos = 0;
- for (int i = 0; i < mItems.size(); i++) {
- final Action action = mItems.get(i);
- if (mKeyguardShowing && !action.showDuringKeyguard()) {
- continue;
- }
- if (!mDeviceProvisioned && !action.showBeforeProvisioning()) {
- continue;
- }
- if (filteredPos == position) {
- return action;
- }
- filteredPos++;
- }
-
- throw new IllegalArgumentException("position " + position + " out of "
- + "range of showable actions, filtered count = "
- + "= " + getCount() + ", keyguardshowing=" + mKeyguardShowing
- + ", provisioned=" + mDeviceProvisioned);
- }
-
-
- public long getItemId(int position) {
- return position;
- }
-
- public View getView(int position, View convertView, ViewGroup parent) {
- Action action = getItem(position);
- return action.create(mContext, (LinearLayout) convertView, LayoutInflater.from(mContext));
- }
- }
-
- // note: the scheme below made more sense when we were planning on having
- // 8 different things in the global actions dialog. seems overkill with
- // only 3 items now, but may as well keep this flexible approach so it will
- // be easy should someone decide at the last minute to include something
- // else, such as 'enable wifi', or 'enable bluetooth'
-
- /**
- * What each item in the global actions dialog must be able to support.
- */
- private interface Action {
- LinearLayout create(Context context, LinearLayout convertView, LayoutInflater inflater);
-
- void onPress();
-
- /**
- * @return whether this action should appear in the dialog when the keygaurd
- * is showing.
- */
- boolean showDuringKeyguard();
-
- /**
- * @return whether this action should appear in the dialog before the
- * device is provisioned.
- */
- boolean showBeforeProvisioning();
- }
-
- /**
- * A single press action maintains no state, just responds to a press
- * and takes an action.
- */
- private static abstract class SinglePressAction implements Action {
- private final int mIconResId;
- private final int mMessageResId;
-
- protected SinglePressAction(int iconResId, int messageResId) {
- mIconResId = iconResId;
- mMessageResId = messageResId;
- }
-
- abstract public void onPress();
-
- public LinearLayout create(Context context, LinearLayout convertView, LayoutInflater inflater) {
- LinearLayout v = (LinearLayout) ((convertView != null) ?
- convertView :
- inflater.inflate(R.layout.global_actions_item, null));
-
- ImageView icon = (ImageView) v.findViewById(R.id.icon);
- TextView messageView = (TextView) v.findViewById(R.id.message);
-
- v.findViewById(R.id.status).setVisibility(View.GONE);
-
- icon.setImageDrawable(context.getResources().getDrawable(mIconResId));
- messageView.setText(mMessageResId);
-
- return v;
- }
- }
-
- /**
- * A toggle action knows whether it is on or off, and displays an icon
- * and status message accordingly.
- */
- static abstract class ToggleAction implements Action {
-
- private boolean mOn = false;
-
- // prefs
- private final int mEnabledIconResId;
- private final int mDisabledIconResid;
- private final int mMessageResId;
- private final int mEnabledStatusMessageResId;
- private final int mDisabledStatusMessageResId;
-
- /**
- * @param enabledIconResId The icon for when this action is on.
- * @param disabledIconResid The icon for when this action is off.
- * @param essage The general information message, e.g 'Silent Mode'
- * @param enabledStatusMessageResId The on status message, e.g 'sound disabled'
- * @param disabledStatusMessageResId The off status message, e.g. 'sound enabled'
- */
- public ToggleAction(int enabledIconResId,
- int disabledIconResid,
- int essage,
- int enabledStatusMessageResId,
- int disabledStatusMessageResId) {
- mEnabledIconResId = enabledIconResId;
- mDisabledIconResid = disabledIconResid;
- mMessageResId = essage;
- mEnabledStatusMessageResId = enabledStatusMessageResId;
- mDisabledStatusMessageResId = disabledStatusMessageResId;
- }
-
- public LinearLayout create(Context context, LinearLayout convertView,
- LayoutInflater inflater) {
- LinearLayout v = (LinearLayout) ((convertView != null) ?
- convertView :
- inflater.inflate(R
- .layout.global_actions_item, null));
-
- ImageView icon = (ImageView) v.findViewById(R.id.icon);
- TextView messageView = (TextView) v.findViewById(R.id.message);
- TextView statusView = (TextView) v.findViewById(R.id.status);
-
- messageView.setText(mMessageResId);
-
- icon.setImageDrawable(context.getResources().getDrawable(
- (mOn ? mEnabledIconResId : mDisabledIconResid)));
- statusView.setText(mOn ? mEnabledStatusMessageResId : mDisabledStatusMessageResId);
- statusView.setVisibility(View.VISIBLE);
-
- return v;
- }
-
- public void onPress() {
- updateState(!mOn);
- onToggle(mOn);
- }
-
- abstract void onToggle(boolean on);
-
- public void updateState(boolean on) {
- mOn = on;
- }
- }
-
- private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
- String reason = intent.getStringExtra(MidWindowManager.SYSTEM_DIALOG_REASON_KEY);
- if (! MidWindowManager.SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS.equals(reason)) {
- mHandler.sendEmptyMessage(MESSAGE_DISMISS);
- }
- }
- }
- };
-
- private static final int MESSAGE_DISMISS = 0;
- private Handler mHandler = new Handler() {
- public void handleMessage(Message msg) {
- if (msg.what == MESSAGE_DISMISS) {
- if (mDialog != null) {
- mDialog.dismiss();
- }
- }
- }
- };
-}
+++ /dev/null
-/*
- * Copyright (C) 2006-2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import java.util.Map;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.LayoutInflater;
-
-public class MidLayoutInflater extends LayoutInflater {
- private static final String[] sClassPrefixList = {
- "android.widget.",
- "android.webkit."
- };
-
- /**
- * Instead of instantiating directly, you should retrieve an instance
- * through {@link Context#getSystemService}
- *
- * @param context The Context in which in which to find resources and other
- * application-specific things.
- *
- * @see Context#getSystemService
- */
- public MidLayoutInflater(Context context) {
- super(context);
- }
-
- protected MidLayoutInflater(LayoutInflater original, Context newContext) {
- super(original, newContext);
- }
-
- /** Override onCreateView to instantiate names that correspond to the
- widgets known to the Widget factory. If we don't find a match,
- call through to our super class.
- */
- @Override protected View onCreateView(String name, AttributeSet attrs) throws ClassNotFoundException {
- for (String prefix : sClassPrefixList) {
- try {
- View view = createView(name, prefix, attrs);
- if (view != null) {
- return view;
- }
- } catch (ClassNotFoundException e) {
- // In this case we want to let the base class take a crack
- // at it.
- }
- }
-
- return super.onCreateView(name, attrs);
- }
-
- public LayoutInflater cloneInContext(Context newContext) {
- return new MidLayoutInflater(this, newContext);
- }
-}
-
+++ /dev/null
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import com.android.internal.view.menu.ContextMenuBuilder;
-import com.android.internal.view.menu.MenuBuilder;
-import com.android.internal.view.menu.MenuDialogHelper;
-import com.android.internal.view.menu.MenuView;
-import com.android.internal.view.menu.SubMenuBuilder;
-
-import android.app.KeyguardManager;
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Configuration;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.media.AudioManager;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.SystemClock;
-import android.provider.CallLog.Calls;
-import android.util.AndroidRuntimeException;
-import android.util.Config;
-import android.util.EventLog;
-import android.util.Log;
-import android.util.SparseArray;
-import android.view.Gravity;
-import android.view.KeyCharacterMap;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import static android.view.ViewGroup.LayoutParams.FILL_PARENT;
-import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import android.view.ViewManager;
-import android.view.VolumePanel;
-import android.view.Window;
-import android.view.WindowManager;
-import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
-import android.view.animation.Animation;
-import android.view.animation.AnimationUtils;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-
-/**
- * Android-specific Window.
- * <p>
- * todo(hackbod): need to pull the generic functionality out into a base class
- * in android.widget.
- */
-public class MidWindow extends Window implements MenuBuilder.Callback {
- private final static String TAG = "MidWindow";
-
- private final static boolean SWEEP_OPEN_MENU = false;
-
- /**
- * Simple callback used by the context menu and its submenus. The options
- * menu submenus do not use this (their behavior is more complex).
- */
- ContextMenuCallback mContextMenuCallback = new ContextMenuCallback(FEATURE_CONTEXT_MENU);
-
- // This is the top-level view of the window, containing the window decor.
- private DecorView mDecor;
-
- // This is the view in which the window contents are placed. It is either
- // mDecor itself, or a child of mDecor where the contents go.
- private ViewGroup mContentParent;
-
- private boolean mIsFloating;
-
- private LayoutInflater mLayoutInflater;
-
- private TextView mTitleView;
-
- private DrawableFeatureState[] mDrawables;
-
- private PanelFeatureState[] mPanels;
-
- /**
- * The panel that is prepared or opened (the most recent one if there are
- * multiple panels). Shortcuts will go to this panel. It gets set in
- * {@link #preparePanel} and cleared in {@link #closePanel}.
- */
- private PanelFeatureState mPreparedPanel;
-
- /**
- * The keycode that is currently held down (as a modifier) for chording. If
- * this is 0, there is no key held down.
- */
- private int mPanelChordingKey;
-
- private ImageView mLeftIconView;
-
- private ImageView mRightIconView;
-
- private ProgressBar mCircularProgressBar;
-
- private ProgressBar mHorizontalProgressBar;
-
- private int mBackgroundResource = 0;
-
- private Drawable mBackgroundDrawable;
-
- private int mFrameResource = 0;
-
- private int mTextColor = 0;
-
- private CharSequence mTitle = null;
-
- private int mTitleColor = 0;
-
- private ContextMenuBuilder mContextMenu;
- private MenuDialogHelper mContextMenuHelper;
-
- private int mVolumeControlStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE;
- private long mVolumeKeyUpTime;
-
- private KeyguardManager mKeyguardManager = null;
-
- private boolean mSearchKeyDownReceived;
-
- private final Handler mKeycodeCallTimeoutHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- if (!mKeycodeCallTimeoutActive) return;
- mKeycodeCallTimeoutActive = false;
- // launch the VoiceDialer
- Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- try {
- getContext().startActivity(intent);
- } catch (ActivityNotFoundException e) {
- startCallActivity();
- }
- }
- };
- private boolean mKeycodeCallTimeoutActive = false;
-
- // Ideally the call and camera buttons would share a common base class, and each implement their
- // own onShortPress() and onLongPress() methods, but to reduce the chance of regressions I'm
- // keeping them separate for now.
- private final Handler mKeycodeCameraTimeoutHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- if (!mKeycodeCameraTimeoutActive) return;
- mKeycodeCameraTimeoutActive = false;
- // Broadcast an intent that the Camera button was longpressed
- Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null);
- intent.putExtra(Intent.EXTRA_KEY_EVENT, (KeyEvent) msg.obj);
- getContext().sendOrderedBroadcast(intent, null);
- }
- };
- private boolean mKeycodeCameraTimeoutActive = false;
-
- public MidWindow(Context context) {
- super(context);
- mLayoutInflater = LayoutInflater.from(context);
- }
-
- @Override
- public final void setContainer(Window container) {
- super.setContainer(container);
- }
-
- @Override
- public boolean requestFeature(int featureId) {
- if (mContentParent != null) {
- throw new AndroidRuntimeException("requestFeature() must be called before adding content");
- }
- final int features = getFeatures();
- if ((features != DEFAULT_FEATURES) && (featureId == FEATURE_CUSTOM_TITLE)) {
-
- /* Another feature is enabled and the user is trying to enable the custom title feature */
- throw new AndroidRuntimeException("You cannot combine custom titles with other title features");
- }
- if (((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) && (featureId != FEATURE_CUSTOM_TITLE)) {
-
- /* Custom title feature is enabled and the user is trying to enable another feature */
- throw new AndroidRuntimeException("You cannot combine custom titles with other title features");
- }
- /* FEATURE_OPENGL disabled for 1.0
- if (featureId == FEATURE_OPENGL) {
- getAttributes().memoryType = WindowManager.LayoutParams.MEMORY_TYPE_GPU;
- }
- */
- return super.requestFeature(featureId);
- }
-
- @Override
- public void setContentView(int layoutResID) {
- if (mContentParent == null) {
- installDecor();
- } else {
- mContentParent.removeAllViews();
- }
- mLayoutInflater.inflate(layoutResID, mContentParent);
- final Callback cb = getCallback();
- if (cb != null) {
- cb.onContentChanged();
- }
- }
-
- @Override
- public void setContentView(View view) {
- setContentView(view, new ViewGroup.LayoutParams(FILL_PARENT, FILL_PARENT));
- }
-
- @Override
- public void setContentView(View view, ViewGroup.LayoutParams params) {
- if (mContentParent == null) {
- installDecor();
- } else {
- mContentParent.removeAllViews();
- }
- mContentParent.addView(view, params);
- final Callback cb = getCallback();
- if (cb != null) {
- cb.onContentChanged();
- }
- }
-
- @Override
- public void addContentView(View view, ViewGroup.LayoutParams params) {
- if (mContentParent == null) {
- installDecor();
- }
- mContentParent.addView(view, params);
- final Callback cb = getCallback();
- if (cb != null) {
- cb.onContentChanged();
- }
- }
-
- @Override
- public View getCurrentFocus() {
- return mDecor != null ? mDecor.findFocus() : null;
- }
-
- @Override
- public boolean isFloating() {
- return mIsFloating;
- }
-
- /**
- * Return a LayoutInflater instance that can be used to inflate XML view layout
- * resources for use in this Window.
- *
- * @return LayoutInflater The shared LayoutInflater.
- */
- @Override
- public LayoutInflater getLayoutInflater() {
- return mLayoutInflater;
- }
-
- @Override
- public void setTitle(CharSequence title) {
- if (mTitleView != null) {
- mTitleView.setText(title);
- }
- mTitle = title;
- }
-
- @Override
- public void setTitleColor(int textColor) {
- if (mTitleView != null) {
- mTitleView.setTextColor(textColor);
- }
- mTitleColor = textColor;
- }
-
- /**
- * Prepares the panel to either be opened or chorded. This creates the Menu
- * instance for the panel and populates it via the Activity callbacks.
- *
- * @param st The panel state to prepare.
- * @param event The event that triggered the preparing of the panel.
- * @return Whether the panel was prepared. If the panel should not be shown,
- * returns false.
- */
- public final boolean preparePanel(PanelFeatureState st, KeyEvent event) {
- // Already prepared (isPrepared will be reset to false later)
- if (st.isPrepared)
- return true;
-
- if ((mPreparedPanel != null) && (mPreparedPanel != st)) {
- // Another Panel is prepared and possibly open, so close it
- closePanel(mPreparedPanel, false);
- }
-
- final Callback cb = getCallback();
-
- 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 (!initializePanelMenu(st) || (st.menu == null)) {
- return false;
- }
- // Call callback, and return if it doesn't want to display menu
- 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;
- st.menu.setQwertyMode(st.qwertyMode);
- }
-
- // Set other state
- st.isPrepared = true;
- st.isHandled = false;
- mPreparedPanel = st;
-
- return true;
- }
-
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- 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();
- menuBuilder.saveHierarchyState(state);
-
- // Remove the menu views since they need to be recreated
- // according to the new configuration
- clearMenuViews(st);
-
- // Re-open the same menu
- reopenMenu(false);
-
- // Restore state
- menuBuilder.restoreHierarchyState(state);
-
- } else {
- // Clear menu views so on next menu opening, it will use
- // the proper layout
- 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
- st.refreshDecorView = true;
-
- ((MenuBuilder) st.menu).clearMenuViews();
- }
-
- @Override
- public final void openPanel(int featureId, KeyEvent event) {
- openPanel(getPanelState(featureId, true), event);
- }
-
- private void openPanel(PanelFeatureState st, KeyEvent event) {
- // System.out.println("Open panel: isOpen=" + st.isOpen);
-
- // Already open, return
- if (st.isOpen) {
- return;
- }
-
- Callback cb = getCallback();
- if ((cb != null) && (!cb.onMenuOpened(st.featureId, st.menu))) {
- // Callback doesn't want the menu to open, reset any state
- closePanel(st, true);
- return;
- }
-
- final WindowManager wm = getWindowManager();
- if (wm == null) {
- return;
- }
-
- // Prepare panel (should have been done before, but just in case)
- if (!preparePanel(st, event)) {
- return;
- }
-
- if (st.decorView == null || st.refreshDecorView) {
- if (st.decorView == null) {
- // Initialize the panel decor, this will populate st.decorView
- if (!initializePanelDecor(st) || (st.decorView == null))
- return;
- } else if (st.refreshDecorView && (st.decorView.getChildCount() > 0)) {
- // Decor needs refreshing, so remove its views
- st.decorView.removeAllViews();
- }
-
- // This will populate st.shownPanelView
- if (!initializePanelContent(st) || (st.shownPanelView == null)) {
- return;
- }
-
- ViewGroup.LayoutParams lp = st.shownPanelView.getLayoutParams();
- if (lp == null) {
- lp = new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
- }
-
- int backgroundResId;
- if (lp.width == ViewGroup.LayoutParams.FILL_PARENT) {
- // If the contents is fill parent for the width, set the
- // corresponding background
- backgroundResId = st.fullBackground;
- } else {
- // Otherwise, set the normal panel background
- backgroundResId = st.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.
- */
- if (!st.shownPanelView.hasFocus()) {
- st.shownPanelView.requestFocus();
- }
- }
-
- st.isOpen = true;
- st.isHandled = false;
-
- WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- WRAP_CONTENT, WRAP_CONTENT,
- st.x, st.y, WindowManager.LayoutParams.TYPE_APPLICATION_PANEL,
- WindowManager.LayoutParams.FLAG_DITHER,
- st.decorView.mDefaultOpacity);
-
- lp.gravity = st.gravity;
- lp.windowAnimations = st.windowAnimations;
- wm.addView(st.decorView, lp);
- // Log.v(TAG, "Adding main menu to window manager.");
- }
-
- @Override
- public final void closePanel(int featureId) {
- closePanel(getPanelState(featureId, true), true);
- }
-
- /**
- * Closes the given panel.
- *
- * @param st The panel to be closed.
- * @param doCallback Whether to notify the callback that the panel was
- * closed. If the panel is in the process of re-opening or
- * opening another panel (e.g., menu opening a sub menu), the
- * callback should not happen and this variable should be false.
- * In addition, this method internally will only perform the
- * callback if the panel is open.
- */
- public final void closePanel(PanelFeatureState st, boolean doCallback) {
- // System.out.println("Close panel: isOpen=" + st.isOpen);
- final ViewManager wm = getWindowManager();
- if ((wm != null) && st.isOpen) {
- if (st.decorView != null) {
- wm.removeView(st.decorView);
- // Log.v(TAG, "Removing main menu from window manager.");
- }
-
- if (doCallback) {
- callOnPanelClosed(st.featureId, st, null);
- }
- }
- st.isPrepared = false;
- st.isHandled = false;
- st.isOpen = false;
-
- // 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
- st.refreshDecorView = true;
- st.isInExpandedMode = false;
- }
-
- if (mPreparedPanel == st) {
- mPreparedPanel = null;
- mPanelChordingKey = 0;
- }
- }
-
- @Override
- public final void togglePanel(int featureId, KeyEvent event) {
- PanelFeatureState st = getPanelState(featureId, true);
- if (st.isOpen) {
- closePanel(st, true);
- } else {
- openPanel(st, event);
- }
- }
-
- /**
- * Called when the panel key is pushed down.
- * @param featureId The feature ID of the relevant panel (defaults to FEATURE_OPTIONS_PANEL}.
- * @param event The key event.
- * @return Whether the key was handled.
- */
- public final boolean onKeyDownPanel(int featureId, KeyEvent event) {
- // The panel key was pushed, so set the chording key
- mPanelChordingKey = event.getKeyCode();
-
- PanelFeatureState st = getPanelState(featureId, true);
- if (!st.isOpen) {
- return preparePanel(st, event);
- }
-
- return false;
- }
-
- /**
- * Called when the panel key is released.
- * @param featureId The feature ID of the relevant panel (defaults to FEATURE_OPTIONS_PANEL}.
- * @param event The key event.
- */
- public final void onKeyUpPanel(int featureId, KeyEvent event) {
- // The panel key was released, so clear the chording key
- mPanelChordingKey = 0;
-
- 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);
- if (audioManager != null) {
- audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
- } else {
- Log.w(TAG, "Couldn't get audio manager");
- }
- }
- }
-
- @Override
- public final void closeAllPanels() {
- final ViewManager wm = getWindowManager();
- if (wm == null) {
- return;
- }
-
- final PanelFeatureState[] panels = mPanels;
- final int N = panels != null ? panels.length : 0;
- for (int i = 0; i < N; i++) {
- final PanelFeatureState panel = panels[i];
- if (panel != null) {
- closePanel(panel, true);
- }
- }
-
- closeContextMenu();
- }
-
- private synchronized void closeContextMenu() {
- mContextMenu = null;
-
- if (mContextMenuHelper != null) {
- mContextMenuHelper.dismiss();
- mContextMenuHelper = null;
- }
- }
-
- @Override
- public boolean performPanelShortcut(int featureId, int keyCode, KeyEvent event, int flags) {
- return performPanelShortcut(getPanelState(featureId, true), keyCode, event, flags);
- }
-
- private boolean performPanelShortcut(PanelFeatureState st, int keyCode, KeyEvent event,
- int flags) {
- if (event.isSystem() || (st == null)) {
- return false;
- }
-
- boolean handled = false;
-
- // Only try to perform menu shortcuts if preparePanel returned true (possible false
- // return value from application not wanting to show the menu).
- if ((st.isPrepared || preparePanel(st, event)) && st.menu != null) {
- // The menu is prepared now, perform the shortcut on it
- handled = st.menu.performShortcut(keyCode, event, flags);
- }
-
- if (handled) {
- // Mark as handled
- st.isHandled = true;
-
- if ((flags & Menu.FLAG_PERFORM_NO_CLOSE) == 0) {
- closePanel(st, true);
- }
- }
-
- return handled;
- }
-
- @Override
- public boolean performPanelIdentifierAction(int featureId, int id, int flags) {
-
- PanelFeatureState st = getPanelState(featureId, true);
- if (!preparePanel(st, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU))) {
- return false;
- }
- if (st.menu == null) {
- return false;
- }
-
- boolean res = st.menu.performIdentifierAction(id, flags);
-
- closePanel(st, true);
-
- return res;
- }
-
- public PanelFeatureState findMenuPanel(Menu menu) {
- final PanelFeatureState[] panels = mPanels;
- final int N = panels != null ? panels.length : 0;
- for (int i = 0; i < N; i++) {
- final PanelFeatureState panel = panels[i];
- if (panel != null && panel.menu == menu) {
- return panel;
- }
- }
- return null;
- }
-
- public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
- final Callback cb = getCallback();
- if (cb != null) {
- final PanelFeatureState panel = findMenuPanel(menu.getRootMenu());
- if (panel != null) {
- return cb.onMenuItemSelected(panel.featureId, item);
- }
- }
- return false;
- }
-
- public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
- final PanelFeatureState panel = findMenuPanel(menu);
- if (panel != null) {
- // Close the panel and only do the callback if the menu is being
- // closed
- // completely, not if opening a sub menu
- closePanel(panel, allMenusAreClosing);
- }
- }
-
- public void onCloseSubMenu(SubMenuBuilder subMenu) {
- final Menu parentMenu = subMenu.getRootMenu();
- final PanelFeatureState panel = findMenuPanel(parentMenu);
-
- // Callback
- if (panel != null) {
- callOnPanelClosed(panel.featureId, panel, parentMenu);
- closePanel(panel, true);
- }
- }
-
- public boolean onSubMenuSelected(final SubMenuBuilder subMenu) {
- if (!subMenu.hasVisibleItems()) {
- return true;
- }
-
- // The window manager will give us a valid window token
- new MenuDialogHelper(subMenu).show(null);
-
- return true;
- }
-
- public void onMenuModeChange(MenuBuilder menu) {
- reopenMenu(true);
- }
-
- private void reopenMenu(boolean toggleMenuMode) {
- PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true);
-
- // Save the future expanded mode state since closePanel will reset it
- boolean newExpandedMode = toggleMenuMode ? !st.isInExpandedMode : st.isInExpandedMode;
-
- st.refreshDecorView = true;
- closePanel(st, false);
-
- // Set the expanded mode state
- st.isInExpandedMode = newExpandedMode;
-
- openPanel(st, null);
- }
-
- /**
- * Initializes the menu associated with the given panel feature state. You
- * must at the very least set PanelFeatureState.menu to the Menu to be
- * associated with the given panel state. The default implementation creates
- * a new menu for the panel state.
- *
- * @param st The panel whose menu is being initialized.
- * @return Whether the initialization was successful.
- */
- protected boolean initializePanelMenu(final PanelFeatureState st) {
- final MenuBuilder menu = new MenuBuilder(getContext());
-
- menu.setCallback(this);
- st.setMenu(menu);
-
- return true;
- }
-
- /**
- * Perform initial setup of a panel. This should at the very least set the
- * style information in the PanelFeatureState and must set
- * PanelFeatureState.decor to the panel's window decor view.
- *
- * @param st The panel being initialized.
- */
- protected boolean initializePanelDecor(PanelFeatureState st) {
- st.decorView = new DecorView(getContext(), st.featureId);
- st.gravity = Gravity.CENTER | Gravity.BOTTOM;
- st.setStyle(getContext());
-
- return true;
- }
-
- /**
- * Initializes the panel associated with the panel feature state. You must
- * at the very least set PanelFeatureState.panel to the View implementing
- * its contents. The default implementation gets the panel from the menu.
- *
- * @param st The panel state being initialized.
- * @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;
- }
-
- st.shownPanelView = menu.getMenuView((st.isInExpandedMode) ? MenuBuilder.TYPE_EXPANDED
- : MenuBuilder.TYPE_ICON, st.decorView);
-
- if (st.shownPanelView != null) {
- // Use the menu View's default animations if it has any
- final int defaultAnimations = ((MenuView) st.shownPanelView).getWindowAnimations();
- if (defaultAnimations != 0) {
- st.windowAnimations = defaultAnimations;
- }
- return true;
- } else {
- return false;
- }
- }
-
- @Override
- public boolean performContextMenuIdentifierAction(int id, int flags) {
- return (mContextMenu != null) ? mContextMenu.performIdentifierAction(id, flags) : false;
- }
-
- @Override
- public final void setBackgroundDrawable(Drawable drawable) {
- if (drawable != mBackgroundDrawable) {
- mBackgroundResource = 0;
- mBackgroundDrawable = drawable;
- if (mDecor != null) {
- mDecor.setWindowBackground(drawable);
- }
- }
- }
-
- @Override
- public final void setFeatureDrawableResource(int featureId, int resId) {
- if (resId != 0) {
- DrawableFeatureState st = getDrawableState(featureId, true);
- if (st.resid != resId) {
- st.resid = resId;
- st.uri = null;
- st.local = getContext().getResources().getDrawable(resId);
- updateDrawable(featureId, st, false);
- }
- } else {
- setFeatureDrawable(featureId, null);
- }
- }
-
- @Override
- public final void setFeatureDrawableUri(int featureId, Uri uri) {
- if (uri != null) {
- DrawableFeatureState st = getDrawableState(featureId, true);
- if (st.uri == null || !st.uri.equals(uri)) {
- st.resid = 0;
- st.uri = uri;
- st.local = loadImageURI(uri);
- updateDrawable(featureId, st, false);
- }
- } else {
- setFeatureDrawable(featureId, null);
- }
- }
-
- @Override
- public final void setFeatureDrawable(int featureId, Drawable drawable) {
- DrawableFeatureState st = getDrawableState(featureId, true);
- st.resid = 0;
- st.uri = null;
- if (st.local != drawable) {
- st.local = drawable;
- updateDrawable(featureId, st, false);
- }
- }
-
- @Override
- public void setFeatureDrawableAlpha(int featureId, int alpha) {
- DrawableFeatureState st = getDrawableState(featureId, true);
- if (st.alpha != alpha) {
- st.alpha = alpha;
- updateDrawable(featureId, st, false);
- }
- }
-
- protected final void setFeatureDefaultDrawable(int featureId, Drawable drawable) {
- DrawableFeatureState st = getDrawableState(featureId, true);
- if (st.def != drawable) {
- st.def = drawable;
- updateDrawable(featureId, st, false);
- }
- }
-
- @Override
- public final void setFeatureInt(int featureId, int value) {
- // XXX Should do more management (as with drawable features) to
- // deal with interactions between multiple window policies.
- updateInt(featureId, value, false);
- }
-
- /**
- * Update the state of a drawable feature. This should be called, for every
- * drawable feature supported, as part of onActive(), to make sure that the
- * contents of a containing window is properly updated.
- *
- * @see #onActive
- * @param featureId The desired drawable feature to change.
- * @param fromActive Always true when called from onActive().
- */
- protected final void updateDrawable(int featureId, boolean fromActive) {
- final DrawableFeatureState st = getDrawableState(featureId, false);
- if (st != null) {
- updateDrawable(featureId, st, fromActive);
- }
- }
-
- /**
- * Called when a Drawable feature changes, for the window to update its
- * graphics.
- *
- * @param featureId The feature being changed.
- * @param drawable The new Drawable to show, or null if none.
- * @param alpha The new alpha blending of the Drawable.
- */
- protected void onDrawableChanged(int featureId, Drawable drawable, int alpha) {
- ImageView view;
- if (featureId == FEATURE_LEFT_ICON) {
- view = getLeftIconView();
- } else if (featureId == FEATURE_RIGHT_ICON) {
- view = getRightIconView();
- } else {
- return;
- }
-
- if (drawable != null) {
- drawable.setAlpha(alpha);
- view.setImageDrawable(drawable);
- view.setVisibility(View.VISIBLE);
- } else {
- view.setVisibility(View.GONE);
- }
- }
-
- /**
- * Called when an int feature changes, for the window to update its
- * graphics.
- *
- * @param featureId The feature being changed.
- * @param value The new integer value.
- */
- protected void onIntChanged(int featureId, int value) {
- if (featureId == FEATURE_PROGRESS || featureId == FEATURE_INDETERMINATE_PROGRESS) {
- updateProgressBars(value);
- } else if (featureId == FEATURE_CUSTOM_TITLE) {
- FrameLayout titleContainer = (FrameLayout) findViewById(com.android.internal.R.id.title_container);
- if (titleContainer != null) {
- mLayoutInflater.inflate(value, titleContainer);
- }
- }
- }
-
- /**
- * Updates the progress bars that are shown in the title bar.
- *
- * @param value Can be one of {@link Window#PROGRESS_VISIBILITY_ON},
- * {@link Window#PROGRESS_VISIBILITY_OFF},
- * {@link Window#PROGRESS_INDETERMINATE_ON},
- * {@link Window#PROGRESS_INDETERMINATE_OFF}, or a value
- * starting at {@link Window#PROGRESS_START} through
- * {@link Window#PROGRESS_END} for setting the default
- * progress (if {@link Window#PROGRESS_END} is given,
- * the progress bar widgets in the title will be hidden after an
- * animation), a value between
- * {@link Window#PROGRESS_SECONDARY_START} -
- * {@link Window#PROGRESS_SECONDARY_END} for the
- * secondary progress (if
- * {@link Window#PROGRESS_SECONDARY_END} is given, the
- * progress bar widgets will still be shown with the secondary
- * progress bar will be completely filled in.)
- */
- private void updateProgressBars(int value) {
- ProgressBar circularProgressBar = getCircularProgressBar(true);
- ProgressBar horizontalProgressBar = getHorizontalProgressBar(true);
-
- final int features = getLocalFeatures();
- if (value == PROGRESS_VISIBILITY_ON) {
- if ((features & (1 << FEATURE_PROGRESS)) != 0) {
- int level = horizontalProgressBar.getProgress();
- int visibility = (horizontalProgressBar.isIndeterminate() || level < 10000) ?
- View.VISIBLE : View.INVISIBLE;
- horizontalProgressBar.setVisibility(visibility);
- }
- if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {
- circularProgressBar.setVisibility(View.VISIBLE);
- }
- } else if (value == PROGRESS_VISIBILITY_OFF) {
- if ((features & (1 << FEATURE_PROGRESS)) != 0) {
- horizontalProgressBar.setVisibility(View.GONE);
- }
- if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {
- circularProgressBar.setVisibility(View.GONE);
- }
- } else if (value == PROGRESS_INDETERMINATE_ON) {
- horizontalProgressBar.setIndeterminate(true);
- } else if (value == PROGRESS_INDETERMINATE_OFF) {
- horizontalProgressBar.setIndeterminate(false);
- } else if (PROGRESS_START <= value && value <= PROGRESS_END) {
- // We want to set the progress value before testing for visibility
- // so that when the progress bar becomes visible again, it has the
- // correct level.
- horizontalProgressBar.setProgress(value - PROGRESS_START);
-
- if (value < PROGRESS_END) {
- showProgressBars(horizontalProgressBar, circularProgressBar);
- } else {
- hideProgressBars(horizontalProgressBar, circularProgressBar);
- }
- } else if (PROGRESS_SECONDARY_START <= value && value <= PROGRESS_SECONDARY_END) {
- horizontalProgressBar.setSecondaryProgress(value - PROGRESS_SECONDARY_START);
-
- showProgressBars(horizontalProgressBar, circularProgressBar);
- }
-
- }
-
- private void showProgressBars(ProgressBar horizontalProgressBar, ProgressBar spinnyProgressBar) {
- final int features = getLocalFeatures();
- if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0 &&
- spinnyProgressBar.getVisibility() == View.INVISIBLE) {
- spinnyProgressBar.setVisibility(View.VISIBLE);
- }
- // Only show the progress bars if the primary progress is not complete
- if ((features & (1 << FEATURE_PROGRESS)) != 0 &&
- horizontalProgressBar.getProgress() < 10000) {
- horizontalProgressBar.setVisibility(View.VISIBLE);
- }
- }
-
- private void hideProgressBars(ProgressBar horizontalProgressBar, ProgressBar spinnyProgressBar) {
- final int features = getLocalFeatures();
- Animation anim = AnimationUtils.loadAnimation(getContext(), com.android.internal.R.anim.fade_out);
- anim.setDuration(1000);
- if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0 &&
- spinnyProgressBar.getVisibility() == View.VISIBLE) {
- spinnyProgressBar.startAnimation(anim);
- spinnyProgressBar.setVisibility(View.INVISIBLE);
- }
- if ((features & (1 << FEATURE_PROGRESS)) != 0 &&
- horizontalProgressBar.getVisibility() == View.VISIBLE) {
- horizontalProgressBar.startAnimation(anim);
- horizontalProgressBar.setVisibility(View.INVISIBLE);
- }
- }
-
- /**
- * Request that key events come to this activity. Use this if your activity
- * has no views with focus, but the activity still wants a chance to process
- * key events.
- */
- @Override
- public void takeKeyEvents(boolean get) {
- mDecor.setFocusable(get);
- }
-
- @Override
- public boolean superDispatchKeyEvent(KeyEvent event) {
- return mDecor.superDispatchKeyEvent(event);
- }
-
- @Override
- public boolean superDispatchTouchEvent(MotionEvent event) {
- return mDecor.superDispatchTouchEvent(event);
- }
-
- @Override
- public boolean superDispatchTrackballEvent(MotionEvent event) {
- return mDecor.superDispatchTrackballEvent(event);
- }
-
- /**
- * A key was pressed down and not handled by anything else in the window.
- *
- * @see #onKeyUp
- * @see android.view.KeyEvent
- */
- protected boolean onKeyDown(int featureId, int keyCode, KeyEvent event) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_VOLUME_UP:
- case KeyEvent.KEYCODE_VOLUME_DOWN: {
- AudioManager audioManager = (AudioManager) getContext().getSystemService(
- Context.AUDIO_SERVICE);
- if (audioManager != null) {
- /*
- * Adjust the volume in on key down since it is more
- * responsive to the user.
- */
- audioManager.adjustSuggestedStreamVolume(
- keyCode == KeyEvent.KEYCODE_VOLUME_UP
- ? AudioManager.ADJUST_RAISE
- : AudioManager.ADJUST_LOWER,
- mVolumeControlStreamType,
- AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE);
- }
- return true;
- }
-
- case KeyEvent.KEYCODE_MUTE:
- 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);
- getContext().sendOrderedBroadcast(intent, null);
- return true;
- }
-
- case KeyEvent.KEYCODE_CAMERA: {
- if (getKeyguardManager().inKeyguardRestrictedInputMode()) {
- break;
- }
- if (event.getRepeatCount() > 0) break;
- mKeycodeCameraTimeoutActive = true;
- mKeycodeCameraTimeoutHandler.removeMessages(0);
- Message message = mKeycodeCameraTimeoutHandler.obtainMessage(0);
- message.obj = event;
- mKeycodeCameraTimeoutHandler.sendMessageDelayed(message,
- ViewConfiguration.getLongPressTimeout());
- return true;
- }
-
- case KeyEvent.KEYCODE_MENU: {
- if (event.getRepeatCount() > 0) break;
- onKeyDownPanel((featureId < 0) ? FEATURE_OPTIONS_PANEL : featureId, event);
- return true;
- }
-
- case KeyEvent.KEYCODE_BACK: {
- if (event.getRepeatCount() > 0) break;
- if (featureId < 0) break;
- if (featureId == FEATURE_OPTIONS_PANEL) {
- PanelFeatureState st = getPanelState(featureId, false);
- if (st != null && st.isInExpandedMode) {
- // If the user is in an expanded menu and hits back, it
- // should go back to the icon menu
- reopenMenu(true);
- return true;
- }
- }
- closePanel(featureId);
- return true;
- }
-
- case KeyEvent.KEYCODE_CALL: {
- if (getKeyguardManager().inKeyguardRestrictedInputMode()) {
- break;
- }
- if (event.getRepeatCount() > 0) break;
- mKeycodeCallTimeoutActive = true;
- mKeycodeCallTimeoutHandler.removeMessages(0);
- mKeycodeCallTimeoutHandler.sendMessageDelayed(
- mKeycodeCallTimeoutHandler.obtainMessage(0),
- ViewConfiguration.getLongPressTimeout());
- return true;
- }
-
- case KeyEvent.KEYCODE_SEARCH: {
- if (event.getRepeatCount() == 0) {
- mSearchKeyDownReceived = true;
- }
- break;
- }
- }
-
- return false;
- }
-
- /**
- * @return A handle to the keyguard manager.
- */
- private KeyguardManager getKeyguardManager() {
- if (mKeyguardManager == null) {
- mKeyguardManager = (KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE);
- }
- return mKeyguardManager;
- }
-
- /**
- * A key was released and not handled by anything else in the window.
- *
- * @see #onKeyDown
- * @see android.view.KeyEvent
- */
- protected boolean onKeyUp(int featureId, int keyCode, KeyEvent event) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_VOLUME_UP:
- case KeyEvent.KEYCODE_VOLUME_DOWN: {
- AudioManager audioManager = (AudioManager) getContext().getSystemService(
- Context.AUDIO_SERVICE);
- if (audioManager != null) {
- /*
- * Play a sound. This is done on key up since we don't want the
- * sound to play when a user holds down volume down to mute.
- */
- audioManager.adjustSuggestedStreamVolume(
- AudioManager.ADJUST_SAME,
- mVolumeControlStreamType,
- AudioManager.FLAG_PLAY_SOUND);
- mVolumeKeyUpTime = SystemClock.uptimeMillis();
- }
- return true;
- }
-
- case KeyEvent.KEYCODE_MENU: {
- onKeyUpPanel(featureId < 0 ? FEATURE_OPTIONS_PANEL : featureId,
- event);
- 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_FORWARD: {
- Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
- intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
- getContext().sendOrderedBroadcast(intent, null);
- return true;
- }
-
- case KeyEvent.KEYCODE_CAMERA: {
- if (getKeyguardManager().inKeyguardRestrictedInputMode()) {
- break;
- }
- if (event.getRepeatCount() > 0) break; // Can a key up event repeat?
- mKeycodeCameraTimeoutHandler.removeMessages(0);
- if (!mKeycodeCameraTimeoutActive) break;
- mKeycodeCameraTimeoutActive = false;
- // Add short press behavior here if desired
- return true;
- }
-
- case KeyEvent.KEYCODE_CALL: {
- if (getKeyguardManager().inKeyguardRestrictedInputMode()) {
- break;
- }
- if (event.getRepeatCount() > 0) break;
- mKeycodeCallTimeoutHandler.removeMessages(0);
- if (!mKeycodeCallTimeoutActive) break;
- mKeycodeCallTimeoutActive = false;
- startCallActivity();
- return true;
- }
-
- case KeyEvent.KEYCODE_SEARCH: {
- /*
- * Do this in onKeyUp since the Search key is also used for
- * chording quick launch shortcuts.
- */
- if (getKeyguardManager().inKeyguardRestrictedInputMode() ||
- !mSearchKeyDownReceived) {
- break;
- }
- mSearchKeyDownReceived = false;
- launchDefaultSearch();
- return true;
- }
- }
-
- return false;
- }
-
- private void startCallActivity() {
- Intent intent = new Intent(Intent.ACTION_VIEW);
- // Note: explicitly set MIME type, because we know what it
- // should be and can't count on every process having access
- // to the contacts provider.
- intent.setDataAndType(Calls.CONTENT_URI, Calls.CONTENT_TYPE);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
- // This intent normally takes us to the Call log. However, the
- // "call_key" extra tells the DialtactsActivity that this action was
- // triggered by a CALL keypress, which is handled specially:
- // we immediately redirect the user to the in-call screen if a call
- // is already in progress (see isSendKeyWhileInCall()).
- intent.putExtra("call_key", true);
-
- getContext().startActivity(intent);
- }
-
- @Override
- protected void onActive() {
- }
-
- @Override
- public final View getDecorView() {
- if (mDecor == null) {
- installDecor();
- }
- return mDecor;
- }
-
- @Override
- public final View peekDecorView() {
- return mDecor;
- }
-
- static private final String FOCUSED_ID_TAG = "android:focusedViewId";
- static private final String VIEWS_TAG = "android:views";
- static private final String PANELS_TAG = "android:Panels";
-
- /** {@inheritDoc} */
- @Override
- public Bundle saveHierarchyState() {
- Bundle outState = new Bundle();
- if (mContentParent == null) {
- return outState;
- }
-
- SparseArray<Parcelable> states = new SparseArray<Parcelable>();
- mContentParent.saveHierarchyState(states);
- outState.putSparseParcelableArray(VIEWS_TAG, states);
-
- // save the focused view id
- View focusedView = mContentParent.findFocus();
- if (focusedView != null) {
- if (focusedView.getId() != View.NO_ID) {
- outState.putInt(FOCUSED_ID_TAG, focusedView.getId());
- } else {
- if (Config.LOGD) {
- Log.d(TAG, "couldn't save which view has focus because the focused view "
- + focusedView + " has no id.");
- }
- }
- }
-
- // save the panels
- SparseArray<Parcelable> panelStates = new SparseArray<Parcelable>();
- savePanelState(panelStates);
- if (panelStates.size() > 0) {
- outState.putSparseParcelableArray(PANELS_TAG, panelStates);
- }
-
- return outState;
- }
-
- /** {@inheritDoc} */
- @Override
- public void restoreHierarchyState(Bundle savedInstanceState) {
- if (mContentParent == null) {
- return;
- }
-
- SparseArray<Parcelable> savedStates
- = savedInstanceState.getSparseParcelableArray(VIEWS_TAG);
- if (savedStates != null) {
- mContentParent.restoreHierarchyState(savedStates);
- }
-
- // restore the focused view
- int focusedViewId = savedInstanceState.getInt(FOCUSED_ID_TAG, View.NO_ID);
- if (focusedViewId != View.NO_ID) {
- View needsFocus = mContentParent.findViewById(focusedViewId);
- if (needsFocus != null) {
- needsFocus.requestFocus();
- } else {
- Log.w(TAG,
- "Previously focused view reported id " + focusedViewId
- + " during save, but can't be found during restore.");
- }
- }
-
- // restore the panels
- SparseArray<Parcelable> panelStates = savedInstanceState.getSparseParcelableArray(PANELS_TAG);
- if (panelStates != null) {
- restorePanelState(panelStates);
- }
- }
-
- /**
- * Invoked when the panels should freeze their state.
- *
- * @param icicles Save state into this. This is usually indexed by the
- * featureId. This will be given to {@link #restorePanelState} in the
- * future.
- */
- private void savePanelState(SparseArray<Parcelable> icicles) {
- PanelFeatureState[] panels = mPanels;
- if (panels == null) {
- return;
- }
-
- for (int curFeatureId = panels.length - 1; curFeatureId >= 0; curFeatureId--) {
- if (panels[curFeatureId] != null) {
- icicles.put(curFeatureId, panels[curFeatureId].onSaveInstanceState());
- }
- }
- }
-
- /**
- * Invoked when the panels should thaw their state from a previously frozen state.
- *
- * @param icicles The state saved by {@link #savePanelState} that needs to be thawed.
- */
- private void restorePanelState(SparseArray<Parcelable> icicles) {
- PanelFeatureState st;
- for (int curFeatureId = icicles.size() - 1; curFeatureId >= 0; curFeatureId--) {
- st = getPanelState(curFeatureId, false /* required */);
- if (st == null) {
- // The panel must not have been required, and is currently not around, skip it
- continue;
- }
-
- st.onRestoreInstanceState(icicles.get(curFeatureId));
- }
-
- /*
- * Implementation note: call openPanelsAfterRestore later to actually open the
- * restored panels.
- */
- }
-
- /**
- * Opens the panels that have had their state restored. This should be
- * called sometime after {@link #restorePanelState} when it is safe to add
- * to the window manager.
- */
- private void openPanelsAfterRestore() {
- PanelFeatureState[] panels = mPanels;
-
- if (panels == null) {
- return;
- }
-
- PanelFeatureState st;
- for (int i = panels.length - 1; i >= 0; i--) {
- st = panels[i];
- if ((st != null) && st.isOpen) {
- // Clear st.isOpen (openPanel will not open if it's already open)
- st.isOpen = false;
- openPanel(st, null);
- }
- }
- }
-
- private final class DecorView extends FrameLayout {
- /* package */int mDefaultOpacity = PixelFormat.OPAQUE;
-
- /** The feature ID of the panel, or -1 if this is the application's DecorView */
- private final int mFeatureId;
-
- private final Rect mDrawingBounds = new Rect();
-
- private final Rect mBackgroundPadding = new Rect();
-
- private final Rect mFramePadding = new Rect();
-
- private final Rect mFrameOffsets = new Rect();
-
- private final Paint mBlackPaint = new Paint();
-
- private boolean mChanging;
-
- private Drawable mMenuBackground;
- private boolean mWatchingForMenu;
- private int mDownY;
-
- public DecorView(Context context, int featureId) {
- super(context);
- mFeatureId = featureId;
- mBlackPaint.setColor(0xFF000000);
- }
-
- @Override
- public boolean dispatchKeyEvent(KeyEvent event) {
- final int keyCode = event.getKeyCode();
- final boolean isDown = event.getAction() == KeyEvent.ACTION_DOWN;
-
- /*
- * If the user hits another key within the play sound delay, then
- * cancel the sound
- */
- if (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_VOLUME_UP
- && mVolumeKeyUpTime + VolumePanel.PLAY_SOUND_DELAY
- > SystemClock.uptimeMillis()) {
- /*
- * The user has hit another key during the delay (e.g., 300ms)
- * since the last volume key up, so cancel any sounds.
- */
- AudioManager audioManager = (AudioManager) getContext().getSystemService(
- Context.AUDIO_SERVICE);
- if (audioManager != null) {
- audioManager.adjustSuggestedStreamVolume(AudioManager.ADJUST_SAME,
- 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.
- if ((mPanelChordingKey > 0) && (mPanelChordingKey != keyCode)) {
- // Perform the shortcut (mPreparedPanel can be null since
- // global shortcuts (such as search) don't rely on a
- // 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
- * and anyone else that may be interested.
- */
- handled = dispatchKeyShortcut(event);
-
- if (handled && mPreparedPanel != null) {
- mPreparedPanel.isHandled = true;
- }
- }
-
- if (handled) {
- return true;
- }
- }
-
- // If a panel is open, perform a shortcut on it without the
- // chorded panel key
- if ((mPreparedPanel != null) && mPreparedPanel.isOpen) {
- if (performPanelShortcut(mPreparedPanel, keyCode, event, 0)) {
- return true;
- }
- }
- }
-
- final Callback cb = getCallback();
- final boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event)
- : super.dispatchKeyEvent(event);
- if (handled) {
- return true;
- }
- return isDown ? MidWindow.this.onKeyDown(mFeatureId, event.getKeyCode(), event)
- : MidWindow.this.onKeyUp(mFeatureId, event.getKeyCode(), event);
- }
-
- private boolean dispatchKeyShortcut(KeyEvent event) {
- View focusedView = findFocus();
- return focusedView == null ? false : focusedView.dispatchKeyShortcutEvent(event);
- }
-
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev) {
- final Callback cb = getCallback();
- return cb != null && mFeatureId < 0 ? cb.dispatchTouchEvent(ev) : super
- .dispatchTouchEvent(ev);
- }
-
- @Override
- public boolean dispatchTrackballEvent(MotionEvent ev) {
- final Callback cb = getCallback();
- return cb != null && mFeatureId < 0 ? cb.dispatchTrackballEvent(ev) : super
- .dispatchTrackballEvent(ev);
- }
-
- public boolean superDispatchKeyEvent(KeyEvent event) {
- return super.dispatchKeyEvent(event);
- }
-
- public boolean superDispatchTouchEvent(MotionEvent event) {
- return super.dispatchTouchEvent(event);
- }
-
- public boolean superDispatchTrackballEvent(MotionEvent event) {
- return super.dispatchTrackballEvent(event);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- return onInterceptTouchEvent(event);
- }
-
- private boolean isOutOfBounds(int x, int y) {
- return x < -5 || y < -5 || x > (getWidth() + 5)
- || y > (getHeight() + 5);
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent event) {
- int action = event.getAction();
- if (mFeatureId >= 0) {
- if (action == MotionEvent.ACTION_DOWN) {
- int x = (int)event.getX();
- int y = (int)event.getY();
- if (isOutOfBounds(x, y)) {
- closePanel(mFeatureId);
- return true;
- }
- }
- }
-
- if (!SWEEP_OPEN_MENU) {
- return false;
- }
-
- if (mFeatureId >= 0) {
- if (action == MotionEvent.ACTION_DOWN) {
- Log.i(TAG, "Watchiing!");
- mWatchingForMenu = true;
- mDownY = (int) event.getY();
- return false;
- }
-
- if (!mWatchingForMenu) {
- return false;
- }
-
- int y = (int)event.getY();
- if (action == MotionEvent.ACTION_MOVE) {
- if (y > (mDownY+30)) {
- Log.i(TAG, "Closing!");
- closePanel(mFeatureId);
- mWatchingForMenu = false;
- return true;
- }
- } else if (action == MotionEvent.ACTION_UP) {
- mWatchingForMenu = false;
- }
-
- return false;
- }
-
- //Log.i(TAG, "Intercept: action=" + action + " y=" + event.getY()
- // + " (in " + getHeight() + ")");
-
- if (action == MotionEvent.ACTION_DOWN) {
- int y = (int)event.getY();
- if (y >= (getHeight()-5) && !hasChildren()) {
- Log.i(TAG, "Watchiing!");
- mWatchingForMenu = true;
- }
- return false;
- }
-
- if (!mWatchingForMenu) {
- return false;
- }
-
- int y = (int)event.getY();
- if (action == MotionEvent.ACTION_MOVE) {
- if (y < (getHeight()-30)) {
- Log.i(TAG, "Opening!");
- openPanel(FEATURE_OPTIONS_PANEL, new KeyEvent(
- KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU));
- mWatchingForMenu = false;
- return true;
- }
- } else if (action == MotionEvent.ACTION_UP) {
- mWatchingForMenu = false;
- }
-
- return false;
- }
-
- @Override
- protected boolean setFrame(int l, int t, int r, int b) {
- boolean changed = super.setFrame(l, t, r, b);
- if (changed) {
- final Rect drawingBounds = mDrawingBounds;
- getDrawingRect(drawingBounds);
-
- Drawable fg = getForeground();
- if (fg != null) {
- final Rect frameOffsets = mFrameOffsets;
- drawingBounds.left += frameOffsets.left;
- drawingBounds.top += frameOffsets.top;
- drawingBounds.right -= frameOffsets.right;
- drawingBounds.bottom -= frameOffsets.bottom;
- fg.setBounds(drawingBounds);
- final Rect framePadding = mFramePadding;
- drawingBounds.left += framePadding.left - frameOffsets.left;
- drawingBounds.top += framePadding.top - frameOffsets.top;
- drawingBounds.right -= framePadding.right - frameOffsets.right;
- drawingBounds.bottom -= framePadding.bottom - frameOffsets.bottom;
- }
-
- Drawable bg = getBackground();
- if (bg != null) {
- bg.setBounds(drawingBounds);
- }
-
- if (SWEEP_OPEN_MENU) {
- if (mMenuBackground == null && mFeatureId < 0
- && getAttributes().height
- == WindowManager.LayoutParams.FILL_PARENT) {
- mMenuBackground = getContext().getResources().getDrawable(
- com.android.internal.R.drawable.menu_background);
- }
- if (mMenuBackground != null) {
- mMenuBackground.setBounds(drawingBounds.left,
- drawingBounds.bottom-6, drawingBounds.right,
- drawingBounds.bottom+20);
- }
- }
- }
- return changed;
- }
-
- @Override
- public void draw(Canvas canvas) {
- super.draw(canvas);
-
- if (mMenuBackground != null) {
- mMenuBackground.draw(canvas);
- }
- }
-
-
- @Override
- public boolean showContextMenuForChild(View originalView) {
- // Reuse the context menu builder
- if (mContextMenu == null) {
- mContextMenu = new ContextMenuBuilder(getContext());
- mContextMenu.setCallback(mContextMenuCallback);
- } else {
- mContextMenu.clearAll();
- }
-
- mContextMenuHelper = mContextMenu.show(originalView, originalView.getWindowToken());
- return mContextMenuHelper != null;
- }
-
- public void startChanging() {
- mChanging = true;
- }
-
- public void finishChanging() {
- mChanging = false;
- drawableChanged();
- }
-
- public void setWindowBackground(Drawable drawable) {
- if (getBackground() != drawable) {
- setBackgroundDrawable(drawable);
- if (drawable != null) {
- drawable.getPadding(mBackgroundPadding);
- } else {
- mBackgroundPadding.setEmpty();
- }
- drawableChanged();
- }
- }
-
- public void setWindowFrame(Drawable drawable) {
- if (getForeground() != drawable) {
- setForeground(drawable);
- if (drawable != null) {
- drawable.getPadding(mFramePadding);
- } else {
- mFramePadding.setEmpty();
- }
- drawableChanged();
- }
- }
-
- @Override
- protected boolean fitSystemWindows(Rect insets) {
- mFrameOffsets.set(insets);
- if (getForeground() != null) {
- drawableChanged();
- }
- return super.fitSystemWindows(insets);
- }
-
- private void drawableChanged() {
- if (mChanging) {
- return;
- }
-
- setPadding(mFramePadding.left + mBackgroundPadding.left, mFramePadding.top
- + mBackgroundPadding.top, mFramePadding.right + mBackgroundPadding.right,
- mFramePadding.bottom + mBackgroundPadding.bottom);
- requestLayout();
- invalidate();
-
- int opacity = PixelFormat.OPAQUE;
-
- // Note: if there is no background, we will assume opaque. The
- // common case seems to be that an application sets there to be
- // no background so it can draw everything itself. For that,
- // we would like to assume OPAQUE and let the app force it to
- // the slower TRANSLUCENT mode if that is really what it wants.
- Drawable bg = getBackground();
- Drawable fg = getForeground();
- if (bg != null) {
- if (fg == null) {
- opacity = bg.getOpacity();
- } else if (mFramePadding.left <= 0 && mFramePadding.top <= 0
- && mFramePadding.right <= 0 && mFramePadding.bottom <= 0) {
- // If the frame padding is zero, then we can be opaque
- // if either the frame -or- the background is opaque.
- int fop = fg.getOpacity();
- int bop = bg.getOpacity();
- if (Config.LOGV)
- Log.v(TAG, "Background opacity: " + bop + ", Frame opacity: " + fop);
- if (fop == PixelFormat.OPAQUE || bop == PixelFormat.OPAQUE) {
- opacity = PixelFormat.OPAQUE;
- } else if (fop == PixelFormat.UNKNOWN) {
- opacity = bop;
- } else if (bop == PixelFormat.UNKNOWN) {
- opacity = fop;
- } else {
- opacity = Drawable.resolveOpacity(fop, bop);
- }
- } else {
- // For now we have to assume translucent if there is a
- // frame with padding... there is no way to tell if the
- // frame and background together will draw all pixels.
- if (Config.LOGV)
- Log.v(TAG, "Padding: " + mFramePadding);
- opacity = PixelFormat.TRANSLUCENT;
- }
- }
-
- if (Config.LOGV)
- Log.v(TAG, "Background: " + bg + ", Frame: " + fg);
- if (Config.LOGV)
- Log.v(TAG, "Selected default opacity: " + opacity);
-
- mDefaultOpacity = opacity;
- if (mFeatureId < 0) {
- setDefaultWindowFormat(opacity);
- }
- }
-
- @Override
- public void onWindowFocusChanged(boolean hasWindowFocus) {
- super.onWindowFocusChanged(hasWindowFocus);
-
- // no KEYCODE_CALL events active across focus changes
- mKeycodeCallTimeoutHandler.removeMessages(0);
- mKeycodeCallTimeoutActive = false;
- mKeycodeCameraTimeoutHandler.removeMessages(0);
- mKeycodeCameraTimeoutActive = false;
-
- // If the user is chording a menu shortcut, release the chord since
- // this window lost focus
- if (!hasWindowFocus && mPanelChordingKey > 0) {
- closePanel(FEATURE_OPTIONS_PANEL);
- }
-
- final Callback cb = getCallback();
- if (cb != null && mFeatureId < 0) {
- cb.onWindowFocusChanged(hasWindowFocus);
- }
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
-
- if (mFeatureId == -1) {
- /*
- * The main window has been attached, try to restore any panels
- * that may have been open before. This is called in cases where
- * an activity is being killed for configuration change and the
- * menu was open. When the activity is recreated, the menu
- * should be shown again.
- */
- openPanelsAfterRestore();
- }
- }
- }
-
- protected DecorView generateDecor() {
- return new DecorView(getContext(), -1);
- }
-
- protected void setFeatureFromAttrs(int featureId, TypedArray attrs,
- int drawableAttr, int alphaAttr) {
- Drawable d = attrs.getDrawable(drawableAttr);
- if (d != null) {
- requestFeature(featureId);
- setFeatureDefaultDrawable(featureId, d);
- }
- if ((getFeatures() & (1 << featureId)) != 0) {
- int alpha = attrs.getInt(alphaAttr, -1);
- if (alpha >= 0) {
- setFeatureDrawableAlpha(featureId, alpha);
- }
- }
- }
-
- protected ViewGroup generateLayout(DecorView decor) {
- // Apply data from current theme.
-
- final Context c = getContext();
- TypedArray a = getWindowStyle();
-
- if (false) {
- System.out.println("From style:");
- String s = "Attrs:";
- for (int i = 0; i < com.android.internal.R.styleable.Window.length; i++) {
- s = s + " " + Integer.toHexString(com.android.internal.R.styleable.Window[i]) + "="
- + a.getString(i);
- }
- System.out.println(s);
- }
-
- mIsFloating = a.getBoolean(com.android.internal.R.styleable.Window_windowIsFloating, false);
- int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR)
- & (~getForcedWindowFlags());
- if (mIsFloating) {
- setLayout(WRAP_CONTENT, WRAP_CONTENT);
- setFlags(0, flagsToUpdate);
-
- /* All dialogs should have the window dimmed */
- WindowManager.LayoutParams params = getAttributes();
- TypedArray attrs = c.obtainStyledAttributes(
- com.android.internal.R.styleable.Theme);
- params.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
- params.dimAmount = attrs.getFloat(
- android.R.styleable.Theme_backgroundDimAmount, 0.5f);
- attrs.recycle();
- } 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);
- }
-
- if (a.getBoolean(com.android.internal.R.styleable.Window_windowFullscreen, false)) {
- setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN&(~getForcedWindowFlags()));
- }
-
- // The rest are only done if this window is not embedded; otherwise,
- // the values are inherited from our container.
- if (getContainer() == null) {
- if (mBackgroundDrawable == null) {
- if (mBackgroundResource == 0) {
- mBackgroundResource = a.getResourceId(
- com.android.internal.R.styleable.Window_windowBackground, 0);
- }
- if (mFrameResource == 0) {
- mFrameResource = a.getResourceId(com.android.internal.R.styleable.Window_windowFrame, 0);
- }
- if (false) {
- System.out.println("Background: "
- + Integer.toHexString(mBackgroundResource) + " Frame: "
- + Integer.toHexString(mFrameResource));
- }
- }
- mTextColor = a.getColor(com.android.internal.R.styleable.Window_textColor, 0xFF000000);
- }
-
- // Inflate the window decor.
-
- int layoutResource;
- int features = getLocalFeatures();
- // System.out.println("Features: 0x" + Integer.toHexString(features));
- if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
- if (mIsFloating) {
- layoutResource = com.android.internal.R.layout.dialog_title_icons;
- } else {
- layoutResource = com.android.internal.R.layout.screen_title_icons;
- }
- // System.out.println("Title Icons!");
- } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0) {
- // Special case for a window with only a progress bar (and title).
- // XXX Need to have a no-title version of embedded windows.
- layoutResource = com.android.internal.R.layout.screen_progress;
- // System.out.println("Progress!");
- } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
- // Special case for a window with a custom title.
- // If the window is floating, we need a dialog layout
- if (mIsFloating) {
- layoutResource = com.android.internal.R.layout.dialog_custom_title;
- } else {
- layoutResource = com.android.internal.R.layout.screen_custom_title;
- }
- } else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
- // If no other features and not embedded, only need a title.
- // If the window is floating, we need a dialog layout
- if (mIsFloating) {
- layoutResource = com.android.internal.R.layout.dialog_title;
- } else {
- layoutResource = com.android.internal.R.layout.screen_title;
- }
- // System.out.println("Title!");
- } else {
- // Embedded, so no decoration is needed.
- layoutResource = com.android.internal.R.layout.screen_simple;
- // System.out.println("Simple!");
- }
-
- mDecor.startChanging();
-
- View in = mLayoutInflater.inflate(layoutResource, null);
- decor.addView(in, new ViewGroup.LayoutParams(FILL_PARENT, FILL_PARENT));
-
- ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
- if (contentParent == null) {
- throw new RuntimeException("Window couldn't find content container view");
- }
-
- if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {
- ProgressBar progress = getCircularProgressBar(false);
- if (progress != null) {
- progress.setIndeterminate(true);
- }
- }
-
- // Remaining setup -- of background and title -- that only applies
- // to top-level windows.
- if (getContainer() == null) {
- Drawable drawable = mBackgroundDrawable;
- if (mBackgroundResource != 0) {
- drawable = getContext().getResources().getDrawable(mBackgroundResource);
- }
- mDecor.setWindowBackground(drawable);
- drawable = null;
- if (mFrameResource != 0) {
- drawable = getContext().getResources().getDrawable(mFrameResource);
- }
- mDecor.setWindowFrame(drawable);
-
- // System.out.println("Text=" + Integer.toHexString(mTextColor) +
- // " Sel=" + Integer.toHexString(mTextSelectedColor) +
- // " Title=" + Integer.toHexString(mTitleColor));
-
- if (mTitleColor == 0) {
- mTitleColor = mTextColor;
- }
-
- if (mTitle != null) {
- setTitle(mTitle);
- }
- setTitleColor(mTitleColor);
- }
-
- mDecor.finishChanging();
-
- return contentParent;
- }
-
- private void installDecor() {
- if (mDecor == null) {
- mDecor = generateDecor();
- mDecor.setIsRootNamespace(true);
- }
- if (mContentParent == null) {
- mContentParent = generateLayout(mDecor);
-
- mTitleView = (TextView)findViewById(com.android.internal.R.id.title);
- if (mTitleView != null) {
- if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {
- View titleContainer = findViewById(com.android.internal.R.id.title_container);
- if (titleContainer != null) {
- titleContainer.setVisibility(View.GONE);
- } else {
- mTitleView.setVisibility(View.GONE);
- }
- if (mContentParent instanceof FrameLayout) {
- ((FrameLayout)mContentParent).setForeground(null);
- }
- } else {
- mTitleView.setText(mTitle);
- }
- }
- }
- }
-
- private Drawable loadImageURI(Uri uri) {
- try {
- return Drawable.createFromStream(
- getContext().getContentResolver().openInputStream(uri), null);
- } catch (Exception e) {
- Log.w(TAG, "Unable to open content: " + uri);
- }
- return null;
- }
-
- private DrawableFeatureState getDrawableState(int featureId, boolean required) {
- if ((getFeatures() & (1 << featureId)) == 0) {
- if (!required) {
- return null;
- }
- throw new RuntimeException("The feature has not been requested");
- }
-
- DrawableFeatureState[] ar;
- if ((ar = mDrawables) == null || ar.length <= featureId) {
- DrawableFeatureState[] nar = new DrawableFeatureState[featureId + 1];
- if (ar != null) {
- System.arraycopy(ar, 0, nar, 0, ar.length);
- }
- mDrawables = ar = nar;
- }
-
- DrawableFeatureState st = ar[featureId];
- if (st == null) {
- ar[featureId] = st = new DrawableFeatureState(featureId);
- }
- return st;
- }
-
- /**
- * 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).
- * @return The panel state.
- */
- 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).
- * @param convertPanelState Optional: If the panel state does not exist, use
- * this as the panel state.
- * @return The panel state.
- */
- private PanelFeatureState getPanelState(int featureId, boolean required,
- PanelFeatureState convertPanelState) {
- if ((getFeatures() & (1 << featureId)) == 0) {
- if (!required) {
- return null;
- }
- throw new RuntimeException("The feature has not been requested");
- }
-
- PanelFeatureState[] ar;
- if ((ar = mPanels) == null || ar.length <= featureId) {
- PanelFeatureState[] nar = new PanelFeatureState[featureId + 1];
- if (ar != null) {
- System.arraycopy(ar, 0, nar, 0, ar.length);
- }
- mPanels = ar = nar;
- }
-
- PanelFeatureState st = ar[featureId];
- if (st == null) {
- ar[featureId] = st = (convertPanelState != null)
- ? convertPanelState
- : new PanelFeatureState(featureId);
- }
- return st;
- }
-
- @Override
- public final void setChildDrawable(int featureId, Drawable drawable) {
- DrawableFeatureState st = getDrawableState(featureId, true);
- st.child = drawable;
- updateDrawable(featureId, st, false);
- }
-
- @Override
- public final void setChildInt(int featureId, int value) {
- updateInt(featureId, value, false);
- }
-
- @Override
- public boolean isShortcutKey(int keyCode, KeyEvent event) {
- PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true);
- return st.menu != null && st.menu.isShortcutKey(keyCode, event);
- }
-
- private void updateDrawable(int featureId, DrawableFeatureState st, 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) {
- return;
- }
-
- final int featureMask = 1 << featureId;
-
- if ((getFeatures() & featureMask) == 0 && !fromResume) {
- return;
- }
-
- Drawable drawable = null;
- if (st != null) {
- drawable = st.child;
- if (drawable == null)
- drawable = st.local;
- if (drawable == null)
- drawable = st.def;
- }
- if ((getLocalFeatures() & featureMask) == 0) {
- if (getContainer() != null) {
- if (isActive() || fromResume) {
- getContainer().setChildDrawable(featureId, drawable);
- }
- }
- } else if (st != null && (st.cur != drawable || st.curAlpha != st.alpha)) {
- // System.out.println("Drawable changed: old=" + st.cur
- // + ", new=" + drawable);
- st.cur = drawable;
- st.curAlpha = st.alpha;
- onDrawableChanged(featureId, drawable, st.alpha);
- }
- }
-
- 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) {
- return;
- }
-
- final int featureMask = 1 << featureId;
-
- if ((getFeatures() & featureMask) == 0 && !fromResume) {
- return;
- }
-
- if ((getLocalFeatures() & featureMask) == 0) {
- if (getContainer() != null) {
- getContainer().setChildInt(featureId, value);
- }
- } else {
- onIntChanged(featureId, value);
- }
- }
-
- private ImageView getLeftIconView() {
- if (mLeftIconView != null) {
- return mLeftIconView;
- }
- if (mContentParent == null) {
- installDecor();
- }
- return (mLeftIconView = (ImageView)findViewById(com.android.internal.R.id.left_icon));
- }
-
- private ProgressBar getCircularProgressBar(boolean shouldInstallDecor) {
- if (mCircularProgressBar != null) {
- return mCircularProgressBar;
- }
- if (mContentParent == null && shouldInstallDecor) {
- installDecor();
- }
- mCircularProgressBar = (ProgressBar)findViewById(com.android.internal.R.id.progress_circular);
- mCircularProgressBar.setVisibility(View.INVISIBLE);
- return mCircularProgressBar;
- }
-
- private ProgressBar getHorizontalProgressBar(boolean shouldInstallDecor) {
- if (mHorizontalProgressBar != null) {
- return mHorizontalProgressBar;
- }
- if (mContentParent == null && shouldInstallDecor) {
- installDecor();
- }
- mHorizontalProgressBar = (ProgressBar)findViewById(com.android.internal.R.id.progress_horizontal);
- mHorizontalProgressBar.setVisibility(View.INVISIBLE);
- return mHorizontalProgressBar;
- }
-
- private ImageView getRightIconView() {
- if (mRightIconView != null) {
- return mRightIconView;
- }
- if (mContentParent == null) {
- installDecor();
- }
- return (mRightIconView = (ImageView)findViewById(com.android.internal.R.id.right_icon));
- }
-
- /**
- * Helper method for calling the {@link Callback#onPanelClosed(int, Menu)}
- * 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.
- * @param menu The menu that was closed. Optional, but give if you have.
- */
- private void callOnPanelClosed(int featureId, PanelFeatureState panel, Menu menu) {
- final Callback cb = getCallback();
- if (cb == null)
- return;
-
- // Try to get a menu
- if (menu == null) {
- // Need a panel to grab the menu, so try to get that
- if (panel == null) {
- if ((featureId >= 0) && (featureId < mPanels.length)) {
- panel = mPanels[featureId];
- }
- }
-
- if (panel != null) {
- // menu still may be null, which is okay--we tried our best
- menu = panel.menu;
- }
- }
-
- // If the panel is not open, do not callback
- if ((panel != null) && (!panel.isOpen))
- return;
-
- cb.onPanelClosed(featureId, menu);
- }
-
- /**
- * 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() {
- final Callback cb = getCallback();
- if (cb == null) {
- return false;
- } else {
- return cb.onSearchRequested();
- }
- }
-
- @Override
- public void setVolumeControlStream(int streamType) {
- mVolumeControlStreamType = streamType;
- }
-
- @Override
- public int getVolumeControlStream() {
- return mVolumeControlStreamType;
- }
-
- private static final class DrawableFeatureState {
- DrawableFeatureState(int _featureId) {
- featureId = _featureId;
- }
-
- final int featureId;
-
- int resid;
-
- Uri uri;
-
- Drawable local;
-
- Drawable child;
-
- Drawable def;
-
- Drawable cur;
-
- int alpha = 255;
-
- int curAlpha = 255;
- }
-
- private static final class PanelFeatureState {
-
- /** Feature ID for this panel. */
- int featureId;
-
- // Information pulled from the style for this panel.
-
- int background;
-
- /** The background when the panel spans the entire available width. */
- int fullBackground;
-
- int gravity;
-
- int x;
-
- int y;
-
- int windowAnimations;
-
- /** Dynamic state of the panel. */
- DecorView decorView;
-
- /** The panel that was returned by onCreatePanelView(). */
- View createdPanelView;
-
- /** The panel that we are actually showing. */
- View shownPanelView;
-
- /** Use {@link #setMenu} to set this. */
- Menu menu;
-
- /**
- * Whether the panel has been prepared (see
- * {@link MidWindow#preparePanel}).
- */
- boolean isPrepared;
-
- /**
- * Whether an item's action has been performed. This happens in obvious
- * scenarios (user clicks on menu item), but can also happen with
- * chording menu+(shortcut key).
- */
- boolean isHandled;
-
- boolean isOpen;
-
- /**
- * True if the menu is in expanded mode, false if the menu is in icon
- * mode
- */
- boolean isInExpandedMode;
-
- public boolean qwertyMode;
-
- boolean refreshDecorView;
-
- /**
- * Contains the state of the menu when told to freeze.
- */
- Bundle frozenMenuState;
-
- PanelFeatureState(int featureId) {
- this.featureId = featureId;
-
- refreshDecorView = false;
- }
-
- void setStyle(Context context) {
- TypedArray a = context.obtainStyledAttributes(com.android.internal.R.styleable.Theme);
- background = a.getResourceId(
- com.android.internal.R.styleable.Theme_panelBackground, 0);
- fullBackground = a.getResourceId(
- com.android.internal.R.styleable.Theme_panelFullBackground, 0);
- windowAnimations = a.getResourceId(
- com.android.internal.R.styleable.Theme_windowAnimationStyle, 0);
- a.recycle();
- }
-
- void setMenu(Menu menu) {
- this.menu = menu;
-
- if (frozenMenuState != null) {
- ((MenuBuilder) menu).restoreHierarchyState(frozenMenuState);
- frozenMenuState = null;
- }
- }
-
- Parcelable onSaveInstanceState() {
- SavedState savedState = new SavedState();
- savedState.featureId = featureId;
- savedState.isOpen = isOpen;
- savedState.isInExpandedMode = isInExpandedMode;
-
- if (menu != null) {
- savedState.menuState = new Bundle();
- ((MenuBuilder) menu).saveHierarchyState(savedState.menuState);
- }
-
- return savedState;
- }
-
- void onRestoreInstanceState(Parcelable state) {
- SavedState savedState = (SavedState) state;
- featureId = savedState.featureId;
- isOpen = savedState.isOpen;
- isInExpandedMode = savedState.isInExpandedMode;
- frozenMenuState = savedState.menuState;
-
- /*
- * A LocalActivityManager keeps the same instance of this class around.
- * The first time the menu is being shown after restoring, the
- * Activity.onCreateOptionsMenu should be called. But, if it is the
- * same instance then menu != null and we won't call that method.
- * So, clear this. Also clear any cached views.
- */
- menu = null;
- createdPanelView = null;
- shownPanelView = null;
- decorView = null;
- }
-
- private static class SavedState implements Parcelable {
- int featureId;
- boolean isOpen;
- boolean isInExpandedMode;
- Bundle menuState;
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(featureId);
- dest.writeInt(isOpen ? 1 : 0);
- dest.writeInt(isInExpandedMode ? 1 : 0);
-
- if (isOpen) {
- 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) {
- return readFromParcel(in);
- }
-
- public SavedState[] newArray(int size) {
- return new SavedState[size];
- }
- };
- }
-
- }
-
- /**
- * Simple implementation of MenuBuilder.Callback that:
- * <li> Opens a submenu when selected.
- * <li> Calls back to the callback's onMenuItemSelected when an item is
- * selected.
- */
- private final class ContextMenuCallback implements MenuBuilder.Callback {
- private int mFeatureId;
-
- public ContextMenuCallback(int featureId) {
- mFeatureId = featureId;
- }
-
- public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
- if (allMenusAreClosing) {
- Callback callback = getCallback();
- if (callback != null) callback.onPanelClosed(mFeatureId, menu);
-
- if (menu == mContextMenu) {
- closeContextMenu();
- }
- }
- }
-
- public void onCloseSubMenu(SubMenuBuilder menu) {
- Callback callback = getCallback();
- if (callback != null) callback.onPanelClosed(mFeatureId, menu.getRootMenu());
- }
-
- public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
- Callback callback = getCallback();
- return (callback != null) && callback.onMenuItemSelected(mFeatureId, item);
-
- }
-
- public void onMenuModeChange(MenuBuilder menu) {
- }
-
- public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
- // Set a simple callback for the submenu
- subMenu.setCallback(this);
-
- // The window manager will give us a valid window token
- new MenuDialogHelper(subMenu).show(null);
-
- return true;
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2006-2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import android.app.Activity;
-import android.app.ActivityManagerNative;
-import android.app.IActivityManager;
-import android.app.IStatusBar;
-import android.content.BroadcastReceiver;
-import android.content.ContentQueryMap;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.LocalPowerManager;
-import android.os.PowerManager;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.provider.Settings;
-import static android.provider.Settings.System.END_BUTTON_BEHAVIOR;
-
-import com.android.internal.policy.PolicyManager;
-import com.android.internal.telephony.ITelephony;
-import android.util.Config;
-import android.util.EventLog;
-import android.util.Log;
-import android.view.HapticFeedbackConstants;
-import android.view.IWindowManager;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.OrientationListener;
-import android.view.RawInputEvent;
-import android.view.Surface;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.Window;
-import android.view.WindowManager;
-import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
-import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
-import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD;
-import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_PHONE;
-import static android.view.WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
-import static android.view.WindowManager.LayoutParams.TYPE_SEARCH_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
-import android.view.WindowManagerImpl;
-import android.view.WindowManagerPolicy;
-import android.view.WindowManagerPolicy.WindowState;
-import android.media.IAudioService;
-import android.media.AudioManager;
-
-import java.util.Observable;
-import java.util.Observer;
-
-/**
- * WindowManagerPolicy implementation for the Android MID UI.
- */
-public class MidWindowManager implements WindowManagerPolicy {
- private static final String TAG = "MidWindowManager";
- private static final boolean DEBUG = false;
- private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
- private static final boolean SHOW_STARTING_ANIMATIONS = true;
-
- private static final int APPLICATION_LAYER = 1;
- private static final int PHONE_LAYER = 2;
- private static final int SEARCH_BAR_LAYER = 3;
- private static final int STATUS_BAR_PANEL_LAYER = 4;
- // toasts and the plugged-in battery thing
- private static final int TOAST_LAYER = 5;
- private static final int STATUS_BAR_LAYER = 6;
- // SIM errors and unlock. Not sure if this really should be in a high layer.
- private static final int PRIORITY_PHONE_LAYER = 7;
- // like the ANR / app crashed dialogs
- private static final int SYSTEM_ALERT_LAYER = 8;
- // system-level error dialogs
- private static final int SYSTEM_ERROR_LAYER = 9;
- // the keyguard; nothing on top of these can take focus, since they are
- // responsible for power management when displayed.
- private static final int KEYGUARD_LAYER = 10;
- private static final int KEYGUARD_DIALOG_LAYER = 11;
- // things in here CAN NOT take focus, but are shown on top of everything else.
- private static final int SYSTEM_OVERLAY_LAYER = 12;
-
- private static final int APPLICATION_PANEL_SUBLAYER = 1;
- private static final int APPLICATION_MEDIA_SUBLAYER = -1;
- private static final int APPLICATION_SUB_PANEL_SUBLAYER = 2;
-
- private static final boolean SINGLE_PRESS_OFF = false;
-
- private static final float SLIDE_TOUCH_EVENT_SIZE_LIMIT = 0.6f;
-
- static public final String SYSTEM_DIALOG_REASON_KEY = "reason";
- static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions";
- static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
-
- private Context mContext;
- private IWindowManager mWindowManager;
- private LocalPowerManager mPowerManager;
-
- boolean mSafeMode;
- private WindowState mStatusBar = null;
- private WindowState mSearchBar = null;
- private WindowState mKeyguard = null;
- private boolean mFirstConnect = true;
- private GlobalActions mGlobalActions;
- private boolean mShouldTurnOffOnKeyUp;
- private RecentApplicationsDialog mRecentAppsDialog;
- private Handler mHandler;
-
- private boolean mLidOpen;
- private boolean mScreenOn = false;
- private int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-
- private int mW, mH;
- private int mCurLeft, mCurTop, mCurRight, mCurBottom;
-
- static final Rect mTmpParentFrame = new Rect();
- static final Rect mTmpDisplayFrame = new Rect();
- static final Rect mTmpVisibleFrame = new Rect();
-
- private WindowState mTopFullscreenOpaqueWindowState;
- private boolean mForceStatusBar;
- private boolean mHomePressed;
- private Intent mHomeIntent;
- private boolean mSearchKeyPressed;
- private boolean mConsumeSearchKeyUp;
-
- private static final int ENDCALL_HOME = 0x1;
- private static final int ENDCALL_SLEEPS = 0x2;
- private static final int DEFAULT_ENDCALL_BEHAVIOR = ENDCALL_SLEEPS;
- private int mEndcallBehavior;
-
- private ShortcutManager mShortcutManager;
- private PowerManager.WakeLock mBroadcastWakeLock;
-
- /*
- * Various use cases for invoking this function
- * screen turning off, should always disable listeners if already enabled
- * screen turned on and current app has sensor based orientation, enable listeners
- * if not already enabled
- * screen turned on and current app does not have sensor orientation, disable listeners if
- * already enabled
- * screen turning on and current app has sensor based orientation, enable listeners if needed
- * screen turning on and current app has nosensor based orientation, do nothing
- */
-
- private Runnable mEndCallLongPress = new Runnable() {
- public void run() {
- mShouldTurnOffOnKeyUp = false;
- sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
- showGlobalActionsDialog();
- }
- };
-
- private void showGlobalActionsDialog() {
- if (mGlobalActions == null) {
- mGlobalActions = new GlobalActions(mContext, mPowerManager);
- }
- mGlobalActions.showDialog(false, isDeviceProvisioned());
- }
-
- private boolean isDeviceProvisioned() {
- return Settings.System.getInt(
- mContext.getContentResolver(), Settings.System.DEVICE_PROVISIONED, 0) != 0;
- }
-
- /**
- * When a home-key longpress expires, close other system windows and launch the recent apps
- */
- private Runnable mHomeLongPress = new Runnable() {
- public void run() {
- /*
- * Eat the longpress so it won't dismiss the recent apps dialog when
- * the user lets go of the home key
- */
- mHomePressed = false;
- sendCloseSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS);
- showRecentAppsDialog();
- }
- };
-
- /**
- * Create (if necessary) and launch the recent apps dialog
- */
- private void showRecentAppsDialog() {
- if (mRecentAppsDialog == null) {
- mRecentAppsDialog = new RecentApplicationsDialog(mContext);
- }
- mRecentAppsDialog.show();
- }
-
- /** {@inheritDoc} */
- public void init(Context context, IWindowManager windowManager,
- LocalPowerManager powerManager) {
- mContext = context;
- mWindowManager = windowManager;
- mPowerManager = powerManager;
- mHandler = new Handler();
- mShortcutManager = new ShortcutManager(context, mHandler);
- mShortcutManager.observe();
- mHomeIntent = new Intent(Intent.ACTION_MAIN, null);
- mHomeIntent.addCategory(Intent.CATEGORY_HOME);
- mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
- mBroadcastWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
- "MidWindowManager.mBroadcastWakeLock");
- }
-
- /** {@inheritDoc} */
- public int checkAddPermission(WindowManager.LayoutParams attrs) {
- int type = attrs.type;
- if (type < WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW
- || type > WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) {
- return WindowManagerImpl.ADD_OKAY;
- }
- String permission = null;
- switch (type) {
- case TYPE_TOAST:
- // XXX right now the app process has complete control over
- // this... should introduce a token to let the system
- // monitor/control what they are doing.
- break;
- case TYPE_PHONE:
- case TYPE_PRIORITY_PHONE:
- case TYPE_SYSTEM_ALERT:
- case TYPE_SYSTEM_ERROR:
- case TYPE_SYSTEM_OVERLAY:
- permission = android.Manifest.permission.SYSTEM_ALERT_WINDOW;
- break;
- default:
- permission = android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
- }
- if (permission != null) {
- if (mContext.checkCallingOrSelfPermission(permission)
- != PackageManager.PERMISSION_GRANTED) {
- return WindowManagerImpl.ADD_PERMISSION_DENIED;
- }
- }
- return WindowManagerImpl.ADD_OKAY;
- }
-
- public void adjustWindowParamsLw(WindowManager.LayoutParams attrs) {
- switch (attrs.type) {
- case TYPE_SYSTEM_OVERLAY:
- case TYPE_TOAST:
- // These types of windows can't receive input events.
- attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
- break;
- }
- }
-
- /** {@inheritDoc} */
- public void adjustConfigurationLw(Configuration config) {
- mPowerManager.setKeyboardVisibility(true);
- config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
- mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
- LocalPowerManager.OTHER_EVENT);
- }
-
- public boolean isCheekPressedAgainstScreen(MotionEvent ev) {
- return false;
- }
-
- /** {@inheritDoc} */
- public int windowTypeToLayerLw(int type) {
- if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
- return APPLICATION_LAYER;
- }
- switch (type) {
- case TYPE_APPLICATION_PANEL:
- return APPLICATION_LAYER;
- case TYPE_APPLICATION_SUB_PANEL:
- return APPLICATION_LAYER;
- case TYPE_STATUS_BAR:
- return STATUS_BAR_LAYER;
- case TYPE_STATUS_BAR_PANEL:
- return STATUS_BAR_PANEL_LAYER;
- case TYPE_SEARCH_BAR:
- return SEARCH_BAR_LAYER;
- case TYPE_PHONE:
- return PHONE_LAYER;
- case TYPE_KEYGUARD:
- return KEYGUARD_LAYER;
- case TYPE_KEYGUARD_DIALOG:
- return KEYGUARD_DIALOG_LAYER;
- case TYPE_SYSTEM_ALERT:
- return SYSTEM_ALERT_LAYER;
- case TYPE_SYSTEM_ERROR:
- return SYSTEM_ERROR_LAYER;
- case TYPE_SYSTEM_OVERLAY:
- return SYSTEM_OVERLAY_LAYER;
- case TYPE_PRIORITY_PHONE:
- return PRIORITY_PHONE_LAYER;
- case TYPE_TOAST:
- return TOAST_LAYER;
- }
- Log.e(TAG, "Unknown window type: " + type);
- return APPLICATION_LAYER;
- }
-
- /** {@inheritDoc} */
- public int subWindowTypeToLayerLw(int type) {
- switch (type) {
- case TYPE_APPLICATION_PANEL:
- return APPLICATION_PANEL_SUBLAYER;
- case TYPE_APPLICATION_MEDIA:
- return APPLICATION_MEDIA_SUBLAYER;
- case TYPE_APPLICATION_SUB_PANEL:
- return APPLICATION_SUB_PANEL_SUBLAYER;
- }
- Log.e(TAG, "Unknown sub-window type: " + type);
- return 0;
- }
-
- /** {@inheritDoc} */
- public View addStartingWindow(IBinder appToken, String packageName,
- int theme, CharSequence nonLocalizedLabel,
- int labelRes, int icon) {
- if (!SHOW_STARTING_ANIMATIONS) {
- return null;
- }
- if (packageName == null) {
- return null;
- }
-
- Context context = mContext;
- boolean setTheme = false;
- //Log.i(TAG, "addStartingWindow " + packageName + ": nonLocalizedLabel="
- // + nonLocalizedLabel + " theme=" + Integer.toHexString(theme));
- if (theme != 0 || labelRes != 0) {
- try {
- context = context.createPackageContext(packageName, 0);
- if (theme != 0) {
- context.setTheme(theme);
- setTheme = true;
- }
- } catch (PackageManager.NameNotFoundException e) {
- }
- }
- if (!setTheme) {
- context.setTheme(com.android.internal.R.style.Theme);
- }
-
- Window win = PolicyManager.makeNewWindow(context);
- Resources r = context.getResources();
- win.setTitle(r.getText(labelRes, nonLocalizedLabel));
-
- win.setType(
- WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
- win.setFlags(
- WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
- WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
-
- win.setLayout(WindowManager.LayoutParams.FILL_PARENT,
- WindowManager.LayoutParams.FILL_PARENT);
-
- final WindowManager.LayoutParams params = win.getAttributes();
- params.token = appToken;
- params.packageName = packageName;
- params.windowAnimations = win.getWindowStyle().getResourceId(
- com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
- params.setTitle("Starting " + packageName);
-
- try {
- WindowManagerImpl wm = (WindowManagerImpl)
- context.getSystemService(Context.WINDOW_SERVICE);
- View view = win.getDecorView();
-
- if (win.isFloating()) {
- // Whoops, there is no way to display an animation/preview
- // of such a thing! After all that work... let's skip it.
- // (Note that we must do this here because it is in
- // getDecorView() where the theme is evaluated... maybe
- // we should peek the floating attribute from the theme
- // earlier.)
- return null;
- }
-
- if (localLOGV) Log.v(
- TAG, "Adding starting window for " + packageName
- + " / " + appToken + ": "
- + (view.getParent() != null ? view : null));
-
- wm.addView(view, params);
-
- // Only return the view if it was successfully added to the
- // window manager... which we can tell by it having a parent.
- return view.getParent() != null ? view : null;
- } catch (WindowManagerImpl.BadTokenException e) {
- // ignore
- Log.w(TAG, appToken + " already running, starting window not displayed");
- }
-
- return null;
- }
-
- /** {@inheritDoc} */
- public void removeStartingWindow(IBinder appToken, View window) {
- // RuntimeException e = new RuntimeException();
- // Log.i(TAG, "remove " + appToken + " " + window, e);
-
- if (localLOGV) Log.v(
- TAG, "Removing starting window for " + appToken + ": " + window);
-
- if (window != null) {
- WindowManagerImpl wm = (WindowManagerImpl) mContext.getSystemService(Context.WINDOW_SERVICE);
- wm.removeView(window);
- }
- }
-
- /**
- * Preflight adding a window to the system.
- *
- * Currently enforces that three window types are singletons:
- * <ul>
- * <li>STATUS_BAR_TYPE</li>
- * <li>SEARCH_BAR_TYPE</li>
- * <li>KEYGUARD_TYPE</li>
- * </ul>
- *
- * @param win The window to be added
- * @param attrs Information about the window to be added
- *
- * @return If ok, WindowManagerImpl.ADD_OKAY. If too many singletons, WindowManagerImpl.ADD_MULTIPLE_SINGLETON
- */
- public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs) {
- switch (attrs.type) {
- case TYPE_STATUS_BAR:
- if (mStatusBar != null) {
- return WindowManagerImpl.ADD_MULTIPLE_SINGLETON;
- }
- mStatusBar = win;
- break;
- case TYPE_SEARCH_BAR:
- if (mSearchBar != null) {
- return WindowManagerImpl.ADD_MULTIPLE_SINGLETON;
- }
- mSearchBar = win;
- break;
- case TYPE_KEYGUARD:
- if (mKeyguard != null) {
- return WindowManagerImpl.ADD_MULTIPLE_SINGLETON;
- }
- mKeyguard = win;
- break;
- }
- return WindowManagerImpl.ADD_OKAY;
- }
-
- /** {@inheritDoc} */
- public void removeWindowLw(WindowState win) {
- if (mStatusBar == win) {
- mStatusBar = null;
- }
- else if (mSearchBar == win) {
- mSearchBar = null;
- }
- else if (mKeyguard == win) {
- mKeyguard = null;
- }
- }
-
- private static final boolean PRINT_ANIM = false;
-
- /** {@inheritDoc} */
- public int selectAnimationLw(WindowState win, int transit) {
- if (PRINT_ANIM) Log.i(TAG, "selectAnimation in " + win
- + ": transit=" + transit);
- if (transit == TRANSIT_PREVIEW_DONE) {
- if (win.hasAppShownWindows()) {
- if (PRINT_ANIM) Log.i(TAG, "**** STARTING EXIT");
- return com.android.internal.R.anim.app_starting_exit;
- }
- }
-
- return 0;
- }
-
- private static IAudioService getAudioInterface() {
- return IAudioService.Stub.asInterface(ServiceManager.checkService(Context.AUDIO_SERVICE));
- }
-
- /** {@inheritDoc} */
- public boolean interceptKeyTi(WindowState win, int code, int metaKeys, boolean down,
- int repeatCount) {
- if (false) {
- Log.d(TAG, "interceptKeyTi code=" + code + " down=" + down + " repeatCount="
- + repeatCount);
- }
-
- // Clear a pending HOME longpress if the user releases Home
- // TODO: This could probably be inside the next bit of logic, but that code
- // turned out to be a bit fragile so I'm doing it here explicitly, for now.
- if ((code == KeyEvent.KEYCODE_HOME) && !down) {
- mHandler.removeCallbacks(mHomeLongPress);
- }
-
- // If the HOME button is currently being held, then we do special
- // chording with it.
- if (mHomePressed) {
-
- // If we have released the home key, and didn't do anything else
- // while it was pressed, then it is time to go home!
- if (code == KeyEvent.KEYCODE_HOME) {
- if (!down) {
- mHomePressed = false;
- launchHomeFromHotKey();
- }
- }
-
- return true;
- }
-
- // First we always handle the home key here, so applications
- // can never break it, although if keyguard is on, we do let
- // it handle it, because that gives us the correct 5 second
- // timeout.
- if (code == KeyEvent.KEYCODE_HOME) {
-
- // If a system window has focus, then it doesn't make sense
- // right now to interact with applications.
- WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null;
- if (attrs != null) {
- int type = attrs.type;
- if (type >= WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW
- && type <= WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) {
- // Only do this once, so home-key-longpress doesn't close itself
- if (repeatCount == 0 && down) {
- sendCloseSystemWindows();
- }
- return false;
- }
- }
-
- if (down && repeatCount == 0) {
- mHandler.postDelayed(mHomeLongPress, ViewConfiguration.getGlobalActionKeyTimeout());
- mHomePressed = true;
- }
- return true;
- } else if (code == KeyEvent.KEYCODE_MENU) {
- // Hijack modified menu keys for debugging features
- final int chordBug = KeyEvent.META_SHIFT_ON;
- final int chordProcess = KeyEvent.META_ALT_ON;
-
- if (down && repeatCount == 0) {
- if ((metaKeys & chordBug) == chordBug) {
- Intent intent = new Intent(Intent.ACTION_BUG_REPORT);
- mContext.sendOrderedBroadcast(intent, null);
- return true;
- } else if ((metaKeys & chordProcess) == chordProcess) {
- Intent service = new Intent();
- service.setClassName(mContext, "com.android.server.LoadAverageService");
- ContentResolver res = mContext.getContentResolver();
- boolean shown = Settings.System.getInt(
- res, Settings.System.SHOW_PROCESSES, 0) != 0;
- if (!shown) {
- mContext.startService(service);
- } else {
- mContext.stopService(service);
- }
- Settings.System.putInt(
- res, Settings.System.SHOW_PROCESSES, shown ? 0 : 1);
- return true;
- }
- }
- } else if (code == KeyEvent.KEYCODE_NOTIFICATION) {
- if (down) {
- // this key doesn't exist on current hardware, but if a device
- // didn't have a touchscreen, it would want one of these to open
- // the status bar.
- IStatusBar sbs = IStatusBar.Stub.asInterface(ServiceManager.getService("statusbar"));
- if (sbs != null) {
- try {
- sbs.toggle();
- } catch (RemoteException e) {
- // we're screwed anyway, since it's in this process
- throw new RuntimeException(e);
- }
- }
- }
- return true;
- } else if (code == KeyEvent.KEYCODE_SEARCH) {
- if (down) {
- if (repeatCount == 0) {
- mSearchKeyPressed = true;
- }
- } else {
- mSearchKeyPressed = false;
-
- if (mConsumeSearchKeyUp) {
- // Consume the up-event
- mConsumeSearchKeyUp = false;
- return true;
- }
- }
- }
-
- // Shortcuts are invoked through Search+key, so intercept those here
- if (mSearchKeyPressed) {
- if (down && repeatCount == 0) {
- Intent shortcutIntent = mShortcutManager.getIntent(code, metaKeys);
- if (shortcutIntent != null) {
- shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- mContext.startActivity(shortcutIntent);
-
- /*
- * We launched an app, so the up-event of the search key
- * should be consumed
- */
- mConsumeSearchKeyUp = true;
- return true;
- }
- }
- }
-
- return false;
- }
-
- /**
- * A home key -> launch home action was detected. Take the appropriate action
- * given the situation with the keyguard.
- */
- private void launchHomeFromHotKey() {
- // no keyguard stuff to worry about, just launch home!
- mContext.startActivity(mHomeIntent);
- sendCloseSystemWindows();
- }
-
- public void getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect coveredInset) {
- final int fl = attrs.flags;
-
- if ((fl &
- (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR))
- == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
- coveredInset.set(mCurLeft, mCurTop, mW - mCurRight, mH - mCurBottom);
- } else {
- coveredInset.setEmpty();
- }
- }
-
- /** {@inheritDoc} */
- public void beginLayoutLw(int displayWidth, int displayHeight) {
- mW = displayWidth;
- mH = displayHeight;
- mCurLeft = 0;
- mCurTop = 0;
- mCurRight = displayWidth;
- mCurBottom = displayHeight;
-
- // decide where the status bar goes ahead of time
- if (mStatusBar != null) {
- final Rect pf = mTmpParentFrame;
- final Rect df = mTmpDisplayFrame;
- final Rect vf = mTmpVisibleFrame;
- pf.left = df.left = vf.left = 0;
- pf.top = df.top = vf.top = 0;
- pf.right = df.right = vf.right = displayWidth;
- pf.bottom = df.bottom = vf.bottom = displayHeight;
-
- mStatusBar.computeFrameLw(pf, df, vf, vf);
- mCurTop = mStatusBar.getFrameLw().bottom;
- }
- }
-
- /** {@inheritDoc} */
- public void layoutWindowLw(WindowState win, WindowManager.LayoutParams attrs, WindowState attached) {
- // we've already done the status bar
- if (win == mStatusBar) {
- return;
- }
-
- final int fl = attrs.flags;
-
- final Rect pf = mTmpParentFrame;
- final Rect df = mTmpDisplayFrame;
- final Rect vf = mTmpVisibleFrame;
-
- if ((fl &
- (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR))
- == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
- df.left = 0;
- df.top = 0;
- df.right = mW;
- df.bottom = mH;
- vf.left = mCurLeft;
- vf.top = mCurTop;
- vf.right = mCurRight;
- vf.bottom = mCurBottom;
- } else if ((fl & FLAG_LAYOUT_IN_SCREEN) == 0) {
- // Make sure this window doesn't intrude into the status bar.
- df.left = vf.left = mCurLeft;
- df.top = vf.top = mCurTop;
- df.right = vf.right = mCurRight;
- df.bottom = vf.bottom = mCurBottom;
- } else {
- df.left = vf.left = 0;
- df.top = vf.top = 0;
- df.right = vf.right = mW;
- df.bottom = vf.bottom = mH;
- }
-
- if (attached != null && (fl & (FLAG_LAYOUT_IN_SCREEN)) == 0) {
- pf.set(attached.getFrameLw());
- } else {
- pf.set(df);
- }
-
- if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0) {
- df.left = df.top = vf.left = vf.top = -10000;
- df.right = df.bottom = vf.right = vf.bottom = 10000;
- }
-
- win.computeFrameLw(pf, df, vf, vf);
- }
-
- /** {@inheritDoc} */
- public void finishLayoutLw() {
- }
-
- /** {@inheritDoc} */
- public void beginAnimationLw(int displayWidth, int displayHeight) {
- mTopFullscreenOpaqueWindowState = null;
- mForceStatusBar = false;
- }
-
- /** {@inheritDoc} */
- public void animatingWindowLw(WindowState win,
- WindowManager.LayoutParams attrs) {
- if (mTopFullscreenOpaqueWindowState == null
- && attrs.type >= FIRST_APPLICATION_WINDOW
- && attrs.type <= LAST_APPLICATION_WINDOW
- && win.fillsScreenLw(mW, mH, true, false)
- && win.isDisplayedLw()) {
- mTopFullscreenOpaqueWindowState = win;
- } else if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
- mForceStatusBar = true;
- }
- }
-
- /** {@inheritDoc} */
- public boolean finishAnimationLw() {
- if (mStatusBar != null) {
- if (mForceStatusBar) {
- mStatusBar.showLw(true);
- } else if (mTopFullscreenOpaqueWindowState != null) {
- WindowManager.LayoutParams lp =
- mTopFullscreenOpaqueWindowState.getAttrs();
- boolean hideStatusBar =
- (lp.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
- if (hideStatusBar) {
- mStatusBar.hideLw(true);
- } else {
- mStatusBar.showLw(true);
- }
- }
- }
- return false;
- }
-
- /** {@inheritDoc} */
- public boolean preprocessInputEventTq(RawInputEvent event) {
- return false;
- }
-
-
- /** {@inheritDoc} */
- public boolean isAppSwitchKeyTqTiLwLi(int keycode) {
- return keycode == KeyEvent.KEYCODE_HOME
- || keycode == KeyEvent.KEYCODE_ENDCALL;
- }
-
- /** {@inheritDoc} */
- public boolean isMovementKeyTi(int keycode) {
- switch (keycode) {
- case KeyEvent.KEYCODE_DPAD_UP:
- case KeyEvent.KEYCODE_DPAD_DOWN:
- case KeyEvent.KEYCODE_DPAD_LEFT:
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- return true;
- }
- return false;
- }
-
- /**
- * @return Whether music is being played right now.
- */
- private boolean isMusicActive() {
- final IAudioService audio = getAudioInterface();
- if (audio == null) {
- Log.w(TAG, "isMusicActive: couldn't get IAudioService reference");
- return false;
- }
- try {
- return audio.isMusicActive();
- } catch (RemoteException e) {
- Log.w(TAG, "IAudioService.isMusicActive() threw RemoteException " + e);
- return false;
- }
- }
-
- /**
- * Tell the audio service to adjust the volume appropriate to the event.
- * @param keycode
- */
- private void sendVolToMusic(int keycode) {
- final IAudioService audio = getAudioInterface();
- if (audio == null) {
- Log.w(TAG, "sendVolToMusic: couldn't get IAudioService reference");
- return;
- }
- try {
- // since audio is playing, we shouldn't have to hold a wake lock
- // during the call, but we do it as a precaution for the rare possibility
- // that the music stops right before we call this
- mBroadcastWakeLock.acquire();
- audio.adjustStreamVolume(
- AudioManager.STREAM_MUSIC,
- keycode == KeyEvent.KEYCODE_VOLUME_UP
- ? AudioManager.ADJUST_RAISE
- : AudioManager.ADJUST_LOWER,
- 0);
- } catch (RemoteException e) {
- Log.w(TAG, "IAudioService.adjustStreamVolume() threw RemoteException " + e);
- } finally {
- mBroadcastWakeLock.release();
- }
- }
-
- /** {@inheritDoc} */
- public int interceptKeyTq(RawInputEvent event, boolean screenIsOn) {
- int result = ACTION_PASS_TO_USER | ACTION_POKE_USER_ACTIVITY;
- return result;
- }
-
- class PassHeadsetKey implements Runnable {
- KeyEvent mKeyEvent;
-
- PassHeadsetKey(KeyEvent keyEvent) {
- mKeyEvent = keyEvent;
- }
-
- public void run() {
- Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
- intent.putExtra(Intent.EXTRA_KEY_EVENT, mKeyEvent);
- mContext.sendOrderedBroadcast(intent, null, mBroadcastDone,
- mHandler, Activity.RESULT_OK, null, null);
- }
- }
-
- private BroadcastReceiver mBroadcastDone = new BroadcastReceiver() {
- public void onReceive(Context context, Intent intent) {
- mBroadcastWakeLock.release();
- }
- };
-
- /** {@inheritDoc} */
- public boolean isWakeRelMovementTq(int device, int classes,
- RawInputEvent event) {
- // if it's tagged with one of the wake bits, it wakes up the device
- return ((event.flags & (FLAG_WAKE | FLAG_WAKE_DROPPED)) != 0);
- }
-
- /** {@inheritDoc} */
- public boolean isWakeAbsMovementTq(int device, int classes,
- RawInputEvent event) {
- // if it's tagged with one of the wake bits, it wakes up the device
- return ((event.flags & (FLAG_WAKE | FLAG_WAKE_DROPPED)) != 0);
- }
-
- /**
- * Given the current state of the world, should this key wake up the device?
- */
- protected boolean isWakeKeyTq(RawInputEvent event) {
- // There are not key maps for trackball devices, but we'd still
- // like to have pressing it wake the device up, so force it here.
- int keycode = event.keycode;
- int flags = event.flags;
- if (keycode == RawInputEvent.BTN_MOUSE) {
- flags |= WindowManagerPolicy.FLAG_WAKE;
- }
- return (flags
- & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
- }
-
- /** {@inheritDoc} */
- public void screenTurnedOff(int why) {
- EventLog.writeEvent(70000, 0);
- mScreenOn = false;
- }
-
- /** {@inheritDoc} */
- public void screenTurnedOn() {
- EventLog.writeEvent(70000, 1);
- mScreenOn = true;
- }
-
- /** {@inheritDoc} */
- public void enableKeyguard(boolean enabled) {
- }
-
- /** {@inheritDoc} */
- public void exitKeyguardSecurely(OnKeyguardExitResult callback) {
- }
-
- /** {@inheritDoc} */
- public boolean keyguardIsShowingTq() {
- return false;
- }
-
- /** {@inheritDoc} */
- public boolean inKeyguardRestrictedKeyInputMode() {
- return false;
- }
-
- /**
- * Callback from {@link KeyguardViewMediator}
- */
- public void onKeyguardShow() {
- sendCloseSystemWindows();
- }
-
- private void sendCloseSystemWindows() {
- sendCloseSystemWindows(null);
- }
-
- private void sendCloseSystemWindows(String reason) {
- Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
- if (reason != null) {
- intent.putExtra(SYSTEM_DIALOG_REASON_KEY, reason);
- }
- mContext.sendBroadcast(intent);
- }
-
- public int rotationForOrientation(int orientation, int lastRotation,
- boolean displayEnabled) {
- // get rid of rotation for now. Always rotation of 0
- return Surface.ROTATION_0;
- }
-
- public boolean detectSafeMode() {
- try {
- int menuState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_MENU);
- mSafeMode = menuState > 0;
- Log.i(TAG, "Menu key state: " + menuState + " safeMode=" + mSafeMode);
- return mSafeMode;
- } catch (RemoteException e) {
- // Doom! (it's also local)
- throw new RuntimeException("window manager dead");
- }
- }
-
- /** {@inheritDoc} */
- public void systemReady() {
- try {
- if (mSafeMode) {
- // If the user is holding the menu key code, then we are
- // going to boot into safe mode.
- ActivityManagerNative.getDefault().enterSafeMode();
- } else {
- // tell the keyguard
- android.os.SystemProperties.set("dev.bootcomplete", "1");
- }
- } catch (RemoteException e) {
- }
- }
-
- /** {@inheritDoc} */
- public void enableScreenAfterBoot() {
- updateRotation();
- }
-
- private void updateRotation() {
- mPowerManager.setKeyboardVisibility(true);
- int rotation = Surface.ROTATION_0;
- try {
- //set orientation on WindowManager
- mWindowManager.setRotation(rotation, true);
- } catch (RemoteException e) {
- }
-
- mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
- LocalPowerManager.OTHER_EVENT);
- }
-
- /**
- * goes to the home screen
- * @return whether it did anything
- */
- boolean goHome() {
- if (false) {
- // This code always brings home to the front.
- mContext.startActivity(mHomeIntent);
- } else {
- // This code brings home to the front or, if it is already
- // at the front, puts the device to sleep.
- try {
- int result = ActivityManagerNative.getDefault()
- .startActivity(null, mHomeIntent,
- mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
- null, 0, null, null, 0, true /* onlyIfNeeded*/, false);
- if (result == IActivityManager.START_RETURN_INTENT_TO_CALLER) {
- return false;
- }
- } catch (RemoteException ex) {
- // bummer, the activity manager, which is in this process, is dead
- }
- }
- sendCloseSystemWindows();
- return true;
- }
-
- public void setCurrentOrientation(int newOrientation) {
- if(newOrientation != mCurrentAppOrientation) {
- mCurrentAppOrientation = newOrientation;
- }
- }
-
- public boolean performHapticFeedback(WindowState win, int effectId, boolean always) {
- return false;
- }
-
- public void screenOnStopped() {
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import android.content.Context;
-
-import com.android.internal.policy.IPolicy;
-import com.android.internal.policy.impl.MidLayoutInflater;
-import com.android.internal.policy.impl.MidWindow;
-import com.android.internal.policy.impl.MidWindowManager;
-
-/**
- * {@hide}
- */
-
-// Simple implementation of the policy interface that spawns the right
-// set of objects
-public class Policy implements IPolicy {
-
- public MidWindow makeNewWindow(Context context) {
- return new MidWindow(context);
- }
-
- public MidLayoutInflater makeNewLayoutInflater(Context context) {
- return new MidLayoutInflater(context);
- }
-
- public MidWindowManager makeNewWindowManager() {
- return new MidWindowManager();
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import com.android.internal.R;
-
-import android.app.Dialog;
-import android.app.StatusBarManager;
-import android.content.Context;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.os.IServiceManager;
-import android.os.LocalPowerManager;
-import android.os.ServiceManager;
-import android.os.ServiceManagerNative;
-import android.os.SystemClock;
-import com.android.internal.telephony.ITelephony;
-import android.view.KeyEvent;
-import android.util.Log;
-import android.view.View;
-import android.view.WindowManager;
-import android.view.View.OnClickListener;
-import android.view.View.OnKeyListener;
-import android.widget.Button;
-
-/**
- * @deprecated use {@link GlobalActions} instead.
- */
-public class PowerDialog extends Dialog implements OnClickListener,
- OnKeyListener {
- private static final String TAG = "PowerDialog";
-
- static private StatusBarManager sStatusBar;
- private Button mKeyguard;
- private Button mPower;
- private Button mRadioPower;
- private Button mSilent;
-
- private LocalPowerManager mPowerManager;
-
- public PowerDialog(Context context, LocalPowerManager powerManager) {
- super(context);
- mPowerManager = powerManager;
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- Context context = getContext();
-
- if (sStatusBar == null) {
- sStatusBar = (StatusBarManager)context.getSystemService(Context.STATUS_BAR_SERVICE);
- }
-
- setContentView(com.android.internal.R.layout.power_dialog);
-
- getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
- getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
- WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
-
- setTitle(context.getText(R.string.power_dialog));
-
- mKeyguard = (Button) findViewById(R.id.keyguard);
- mPower = (Button) findViewById(R.id.off);
- mRadioPower = (Button) findViewById(R.id.radio_power);
- mSilent = (Button) findViewById(R.id.silent);
-
- if (mKeyguard != null) {
- mKeyguard.setOnKeyListener(this);
- mKeyguard.setOnClickListener(this);
- }
- if (mPower != null) {
- mPower.setOnClickListener(this);
- }
- if (mRadioPower != null) {
- mRadioPower.setOnClickListener(this);
- }
- if (mSilent != null) {
- mSilent.setOnClickListener(this);
- // XXX: HACK for now hide the silent until we get mute support
- mSilent.setVisibility(View.GONE);
- }
-
- CharSequence text;
-
- // set the keyguard button's text
- text = context.getText(R.string.screen_lock);
- mKeyguard.setText(text);
- mKeyguard.requestFocus();
-
- try {
- ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
- if (phone != null) {
- text = phone.isRadioOn() ? context
- .getText(R.string.turn_off_radio) : context
- .getText(R.string.turn_on_radio);
- }
- } catch (RemoteException ex) {
- // ignore it
- }
-
- mRadioPower.setText(text);
- }
-
- public void onClick(View v) {
- this.dismiss();
- if (v == mPower) {
- // shutdown by making sure radio and power are handled accordingly.
- ShutdownThread.shutdownAfterDisablingRadio(getContext(), true);
- } else if (v == mRadioPower) {
- try {
- ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
- if (phone != null) {
- phone.toggleRadioOnOff();
- }
- } catch (RemoteException ex) {
- // ignore it
- }
- } else if (v == mSilent) {
- // do something
- } else if (v == mKeyguard) {
- if (v.isInTouchMode()) {
- // only in touch mode for the reasons explained in onKey.
- this.dismiss();
- mPowerManager.goToSleep(SystemClock.uptimeMillis() + 1);
- }
- }
- }
-
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- // The activate keyguard button needs to put the device to sleep on the
- // key up event. If we try to put it to sleep on the click or down
- // action
- // the the up action will cause the device to wake back up.
-
- // Log.i(TAG, "keyCode: " + keyCode + " action: " + event.getAction());
- if (keyCode != KeyEvent.KEYCODE_DPAD_CENTER
- || event.getAction() != KeyEvent.ACTION_UP) {
- // Log.i(TAG, "getting out of dodge...");
- return false;
- }
-
- // Log.i(TAG, "Clicked mKeyguard! dimissing dialog");
- this.dismiss();
- // Log.i(TAG, "onKey: turning off the screen...");
- // XXX: arve says this is a hack for now
- mPowerManager.goToSleep(event.getEventTime() + 1);
- return true;
- }
-
- public void show() {
- super.show();
- Log.d(TAG, "show... disabling expand");
- sStatusBar.disable(StatusBarManager.DISABLE_EXPAND);
- }
-
- public void dismiss() {
- super.dismiss();
- Log.d(TAG, "dismiss... reenabling expand");
- sStatusBar.disable(StatusBarManager.DISABLE_NONE);
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import android.app.ActivityManager;
-import android.app.Dialog;
-import android.app.StatusBarManager;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.view.View;
-import android.view.Window;
-import android.view.WindowManager;
-import android.view.View.OnClickListener;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import java.util.List;
-
-public class RecentApplicationsDialog extends Dialog implements OnClickListener {
- // Elements for debugging support
-// private static final String LOG_TAG = "RecentApplicationsDialog";
- private static final boolean DBG_FORCE_EMPTY_LIST = false;
-
- static private StatusBarManager sStatusBar;
-
- private static final int NUM_BUTTONS = 6;
- private static final int MAX_RECENT_TASKS = NUM_BUTTONS * 2; // allow for some discards
-
- final View[] mButtons = new View[NUM_BUTTONS];
- View mNoAppsText;
- IntentFilter mBroadcastIntentFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
-
- public RecentApplicationsDialog(Context context) {
- super(context);
- }
-
- /**
- * We create the recent applications dialog just once, and it stays around (hidden)
- * until activated by the user.
- *
- * @see MidWindowManager#showRecentAppsDialog
- */
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- Context context = getContext();
-
- if (sStatusBar == null) {
- sStatusBar = (StatusBarManager)context.getSystemService(Context.STATUS_BAR_SERVICE);
- }
-
- Window theWindow = getWindow();
- theWindow.requestFeature(Window.FEATURE_NO_TITLE);
- theWindow.setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
- theWindow.setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
- WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
-
- setContentView(com.android.internal.R.layout.recent_apps_dialog);
-
- mButtons[0] = findViewById(com.android.internal.R.id.button1);
- mButtons[1] = findViewById(com.android.internal.R.id.button2);
- mButtons[2] = findViewById(com.android.internal.R.id.button3);
- mButtons[3] = findViewById(com.android.internal.R.id.button4);
- mButtons[4] = findViewById(com.android.internal.R.id.button5);
- mButtons[5] = findViewById(com.android.internal.R.id.button6);
- mNoAppsText = findViewById(com.android.internal.R.id.no_applications_message);
-
- for (View b : mButtons) {
- b.setOnClickListener(this);
- }
- }
-
- /**
- * Handler for user clicks. If a button was clicked, launch the corresponding activity.
- */
- public void onClick(View v) {
-
- for (View b : mButtons) {
- if (b == v) {
- // prepare a launch intent and send it
- Intent intent = (Intent)b.getTag();
- getContext().startActivity(intent);
- }
- }
- dismiss();
- }
-
- /**
- * Set up and show the recent activities dialog.
- */
- @Override
- public void onStart() {
- super.onStart();
- reloadButtons();
- if (sStatusBar != null) {
- sStatusBar.disable(StatusBarManager.DISABLE_EXPAND);
- }
-
- // receive broadcasts
- getContext().registerReceiver(mBroadcastReceiver, mBroadcastIntentFilter);
- }
-
- /**
- * Dismiss the recent activities dialog.
- */
- @Override
- public void onStop() {
- super.onStop();
-
- // dump extra memory we're hanging on to
- for (View b : mButtons) {
- setButtonAppearance(b, null, null);
- b.setTag(null);
- }
-
- if (sStatusBar != null) {
- sStatusBar.disable(StatusBarManager.DISABLE_NONE);
- }
-
- // stop receiving broadcasts
- getContext().unregisterReceiver(mBroadcastReceiver);
- }
-
- /**
- * Reload the 6 buttons with recent activities
- */
- private void reloadButtons() {
-
- final Context context = getContext();
- final PackageManager pm = context.getPackageManager();
- final ActivityManager am = (ActivityManager)
- context.getSystemService(Context.ACTIVITY_SERVICE);
- final List<ActivityManager.RecentTaskInfo> recentTasks =
- am.getRecentTasks(MAX_RECENT_TASKS, 0);
-
- ResolveInfo homeInfo = pm.resolveActivity(
- new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME),
- 0);
-
- // Performance note: Our android performance guide says to prefer Iterator when
- // using a List class, but because we know that getRecentTasks() always returns
- // an ArrayList<>, we'll use a simple index instead.
- int button = 0;
- int numTasks = recentTasks.size();
- for (int i = 0; i < numTasks && (button < NUM_BUTTONS); ++i) {
- final ActivityManager.RecentTaskInfo info = recentTasks.get(i);
-
- // for debug purposes only, disallow first result to create empty lists
- if (DBG_FORCE_EMPTY_LIST && (i == 0)) continue;
-
- Intent intent = new Intent(info.baseIntent);
- if (info.origActivity != null) {
- intent.setComponent(info.origActivity);
- }
-
- // Skip the current home activity.
- if (homeInfo != null) {
- if (homeInfo.activityInfo.packageName.equals(
- intent.getComponent().getPackageName())
- && homeInfo.activityInfo.name.equals(
- intent.getComponent().getClassName())) {
- continue;
- }
- }
-
- intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
- | Intent.FLAG_ACTIVITY_NEW_TASK);
- final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
- if (resolveInfo != null) {
- final ActivityInfo activityInfo = resolveInfo.activityInfo;
- final String title = activityInfo.loadLabel(pm).toString();
- final Drawable icon = activityInfo.loadIcon(pm);
-
- if (title != null && title.length() > 0 && icon != null) {
- final View b = mButtons[button];
- setButtonAppearance(b, title, icon);
- b.setTag(intent);
- b.setVisibility(View.VISIBLE);
- b.setPressed(false);
- b.clearFocus();
- ++button;
- }
- }
- }
-
- // handle the case of "no icons to show"
- mNoAppsText.setVisibility((button == 0) ? View.VISIBLE : View.GONE);
-
- // hide the rest
- for ( ; button < NUM_BUTTONS; ++button) {
- mButtons[button].setVisibility(View.GONE);
- }
- }
-
- /**
- * Adjust appearance of each icon-button
- */
- private void setButtonAppearance(View theButton, final String theTitle, final Drawable icon) {
- TextView tv = (TextView) theButton.findViewById(com.android.internal.R.id.label);
- tv.setText(theTitle);
- ImageView iv = (ImageView) theButton.findViewById(com.android.internal.R.id.icon);
- iv.setImageDrawable(icon);
- }
-
- /**
- * This is the listener for the ACTION_CLOSE_SYSTEM_DIALOGS intent. It's an indication that
- * we should close ourselves immediately, in order to allow a higher-priority UI to take over
- * (e.g. phone call received).
- *
- * TODO: This is a really heavyweight solution for something that should be so simple.
- * For example, we already have a handler, in our superclass, why aren't we sharing that?
- * I think we need to investigate simplifying this entire methodology, or perhaps boosting
- * it up into the Dialog class.
- */
- private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
- String reason = intent.getStringExtra(MidWindowManager.SYSTEM_DIALOG_REASON_KEY);
- if (! MidWindowManager.SYSTEM_DIALOG_REASON_RECENT_APPS.equals(reason)) {
- dismiss();
- }
- }
- }
- };
-}
+++ /dev/null
-/**
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy
- * of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import android.content.Context;
-import android.content.Intent;
-import android.database.ContentObserver;
-import android.database.Cursor;
-import android.os.Handler;
-import android.provider.Settings;
-import android.util.Log;
-import android.util.SparseArray;
-import android.view.KeyCharacterMap;
-
-import java.net.URISyntaxException;
-
-/**
- * Manages quick launch shortcuts by:
- * <li> Keeping the local copy in sync with the database (this is an observer)
- * <li> Returning a shortcut-matching intent to clients
- */
-class ShortcutManager extends ContentObserver {
-
- private static final String TAG = "ShortcutManager";
-
- private static final int COLUMN_SHORTCUT = 0;
- private static final int COLUMN_INTENT = 1;
- private static final String[] sProjection = new String[] {
- Settings.Bookmarks.SHORTCUT, Settings.Bookmarks.INTENT
- };
-
- private Context mContext;
- private Cursor mCursor;
- /** Map of a shortcut to its intent. */
- private SparseArray<Intent> mShortcutIntents;
-
- public ShortcutManager(Context context, Handler handler) {
- super(handler);
-
- mContext = context;
- mShortcutIntents = new SparseArray<Intent>();
- }
-
- /** Observes the provider of shortcut+intents */
- public void observe() {
- mCursor = mContext.getContentResolver().query(
- Settings.Bookmarks.CONTENT_URI, sProjection, null, null, null);
- mCursor.registerContentObserver(this);
- updateShortcuts();
- }
-
- @Override
- public void onChange(boolean selfChange) {
- updateShortcuts();
- }
-
- private void updateShortcuts() {
- Cursor c = mCursor;
- if (!c.requery()) {
- Log.e(TAG, "ShortcutObserver could not re-query shortcuts.");
- return;
- }
-
- mShortcutIntents.clear();
- while (c.moveToNext()) {
- int shortcut = c.getInt(COLUMN_SHORTCUT);
- if (shortcut == 0) continue;
- String intentURI = c.getString(COLUMN_INTENT);
- Intent intent = null;
- try {
- intent = Intent.getIntent(intentURI);
- } catch (URISyntaxException e) {
- Log.w(TAG, "Intent URI for shortcut invalid.", e);
- }
- if (intent == null) continue;
- mShortcutIntents.put(shortcut, intent);
- }
- }
-
- /**
- * Gets the shortcut intent for a given keycode+modifier. Make sure you
- * strip whatever modifier is used for invoking shortcuts (for example,
- * if 'Sym+A' should invoke a shortcut on 'A', you should strip the
- * 'Sym' bit from the modifiers before calling this method.
- * <p>
- * This will first try an exact match (with modifiers), and then try a
- * match without modifiers (primary character on a key).
- *
- * @param keyCode The keycode of the key pushed.
- * @param modifiers The modifiers without any that are used for chording
- * to invoke a shortcut.
- * @return The intent that matches the shortcut, or null if not found.
- */
- public Intent getIntent(int keyCode, int modifiers) {
- KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.BUILT_IN_KEYBOARD);
- // First try the exact keycode (with modifiers)
- int shortcut = kcm.get(keyCode, modifiers);
- Intent intent = shortcut != 0 ? mShortcutIntents.get(shortcut) : null;
- if (intent != null) return intent;
-
- // Next try the keycode without modifiers (the primary character on that key)
- shortcut = Character.toLowerCase(kcm.get(keyCode, 0));
- return shortcut != 0 ? mShortcutIntents.get(shortcut) : null;
- }
-
-}
+++ /dev/null
- /*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import android.app.ProgressDialog;
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.os.RemoteException;
-import android.os.Power;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import com.android.internal.telephony.ITelephony;
-import android.util.Log;
-import android.view.WindowManager;
-
-
-final class ShutdownThread extends Thread {
- // constants
- private static final String TAG = "ShutdownThread";
- private static final int MAX_NUM_PHONE_STATE_READS = 16;
- private static final int PHONE_STATE_POLL_SLEEP_MSEC = 500;
- private static final ITelephony sPhone =
- ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
-
- // state tracking
- private static Object sIsStartedGuard = new Object();
- private static boolean sIsStarted = false;
-
- // static instance of this thread
- private static final ShutdownThread sInstance = new ShutdownThread();
-
- private ShutdownThread() {
- }
-
- /**
- * request a shutdown.
- *
- * @param context Context used to display the shutdown progress dialog.
- */
- public static void shutdownAfterDisablingRadio(final Context context, boolean confirm){
- // ensure that only one thread is trying to power down.
- // any additional calls are just returned
- synchronized (sIsStartedGuard){
- if (sIsStarted) {
- Log.d(TAG, "Request to shutdown already running, returning.");
- return;
- }
- }
-
- Log.d(TAG, "Notifying thread to start radio shutdown");
-
- if (confirm) {
- final AlertDialog dialog = new AlertDialog.Builder(context)
- .setIcon(android.R.drawable.ic_dialog_alert)
- .setTitle(com.android.internal.R.string.power_off)
- .setMessage(com.android.internal.R.string.shutdown_confirm)
- .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- beginShutdownSequence(context);
- }
- })
- .setNegativeButton(com.android.internal.R.string.no, null)
- .create();
- dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
- dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
- dialog.show();
- } else {
- beginShutdownSequence(context);
- }
- }
-
- private static void beginShutdownSequence(Context context) {
- synchronized (sIsStartedGuard) {
- sIsStarted = true;
- }
-
- // throw up an indeterminate system dialog to indicate radio is
- // shutting down.
- ProgressDialog pd = new ProgressDialog(context);
- pd.setTitle(context.getText(com.android.internal.R.string.power_off));
- pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
- pd.setIndeterminate(true);
- pd.setCancelable(false);
- pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
- pd.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
-
- pd.show();
-
- // start the thread that initiates shutdown
- sInstance.start();
- }
-
- /**
- * Makes sure we handle the shutdown gracefully.
- * Shuts off power regardless of radio state if the alloted time has passed.
- */
- public void run() {
- //shutdown the phone radio if possible.
- if (sPhone != null) {
- try {
- //shutdown radio
- sPhone.setRadio(false);
-
- for (int i = 0; i < MAX_NUM_PHONE_STATE_READS; i++){
- // poll radio up to 64 times, with a 0.5 sec delay between each call,
- // totaling 32 sec.
- if (!sPhone.isRadioOn()) {
- Log.d(TAG, "Radio shutdown complete.");
- break;
- }
- SystemClock.sleep(PHONE_STATE_POLL_SLEEP_MSEC);
- }
- } catch (RemoteException ex) {
- Log.e(TAG, "RemoteException caught from failed radio shutdown.", ex);
- }
- }
-
- //shutdown power
- Log.d(TAG, "Shutting down power.");
- Power.shutdown();
- }
-}
+++ /dev/null
-<body>
-
-{@hide}
-
-</body>
+++ /dev/null
-LOCAL_PATH:= $(call my-dir)
-
-# the library
-# ============================================================
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
- $(call all-subdir-java-files)
-
-LOCAL_MODULE := android.policy_phone
-LOCAL_UNINSTALLABLE_MODULE := true
-
-include $(BUILD_JAVA_LIBRARY)
+++ /dev/null
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import com.android.internal.R;
-import com.android.internal.widget.LockPatternUtils;
-
-import android.accounts.AccountsServiceConstants;
-import android.accounts.IAccountsService;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.graphics.Rect;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.text.Editable;
-import android.text.InputFilter;
-import android.text.LoginFilter;
-import android.text.TextWatcher;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.RelativeLayout;
-import android.widget.TextView;
-
-/**
- * When the user forgets their password a bunch of times, we fall back on their
- * account's login/password to unlock the phone (and reset their lock pattern).
- *
- * <p>This class is useful only on platforms that support the
- * IAccountsService.
- */
-public class AccountUnlockScreen extends RelativeLayout implements KeyguardScreen,
- View.OnClickListener, ServiceConnection, TextWatcher {
-
-
- private static final String LOCK_PATTERN_PACKAGE = "com.android.settings";
- private static final String LOCK_PATTERN_CLASS =
- "com.android.settings.ChooseLockPattern";
-
- /**
- * The amount of millis to stay awake once this screen detects activity
- */
- private static final int AWAKE_POKE_MILLIS = 30000;
-
- private final KeyguardScreenCallback mCallback;
- private final LockPatternUtils mLockPatternUtils;
- private IAccountsService mAccountsService;
-
- private TextView mTopHeader;
- private TextView mInstructions;
- private EditText mLogin;
- private EditText mPassword;
- private Button mOk;
- private Button mEmergencyCall;
-
- /**
- * AccountUnlockScreen constructor.
- *
- * @throws IllegalStateException if the IAccountsService is not
- * available on the current platform.
- */
- public AccountUnlockScreen(Context context,
- KeyguardScreenCallback callback,
- LockPatternUtils lockPatternUtils) {
- super(context);
- mCallback = callback;
- mLockPatternUtils = lockPatternUtils;
-
- LayoutInflater.from(context).inflate(
- R.layout.keyguard_screen_glogin_unlock, this, true);
-
- mTopHeader = (TextView) findViewById(R.id.topHeader);
-
- mInstructions = (TextView) findViewById(R.id.instructions);
-
- mLogin = (EditText) findViewById(R.id.login);
- mLogin.setFilters(new InputFilter[] { new LoginFilter.UsernameFilterGeneric() } );
- mLogin.addTextChangedListener(this);
-
- mPassword = (EditText) findViewById(R.id.password);
- mPassword.addTextChangedListener(this);
-
- mOk = (Button) findViewById(R.id.ok);
- mOk.setOnClickListener(this);
-
- mEmergencyCall = (Button) findViewById(R.id.emergencyCall);
- mEmergencyCall.setOnClickListener(this);
-
- Log.v("AccountUnlockScreen", "debug: Connecting to accounts service");
- final boolean connected = mContext.bindService(AccountsServiceConstants.SERVICE_INTENT,
- this, Context.BIND_AUTO_CREATE);
- if (!connected) {
- Log.v("AccountUnlockScreen", "debug: Couldn't connect to accounts service");
- throw new IllegalStateException("couldn't bind to accounts service");
- }
- }
-
- public void afterTextChanged(Editable s) {
- }
-
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- }
-
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- mCallback.pokeWakelock(AWAKE_POKE_MILLIS);
- }
-
- @Override
- protected boolean onRequestFocusInDescendants(int direction,
- Rect previouslyFocusedRect) {
- // send focus to the login field
- return mLogin.requestFocus(direction, previouslyFocusedRect);
- }
-
- /** {@inheritDoc} */
- public boolean needsInput() {
- return true;
- }
-
- /** {@inheritDoc} */
- public void onPause() {
-
- }
-
- /** {@inheritDoc} */
- public void onResume() {
- // start fresh
- mLogin.setText("");
- mPassword.setText("");
- mLogin.requestFocus();
- }
-
- /** {@inheritDoc} */
- public void cleanUp() {
- mContext.unbindService(this);
- }
-
- /** {@inheritDoc} */
- public void onClick(View v) {
- mCallback.pokeWakelock();
- if (v == mOk) {
- if (checkPassword()) {
- // clear out forgotten password
- mLockPatternUtils.setPermanentlyLocked(false);
-
- // launch the 'choose lock pattern' activity so
- // the user can pick a new one if they want to
- Intent intent = new Intent();
- intent.setClassName(LOCK_PATTERN_PACKAGE, LOCK_PATTERN_CLASS);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- mContext.startActivity(intent);
-
- // close the keyguard
- mCallback.keyguardDone(true);
- } else {
- mInstructions.setText(R.string.lockscreen_glogin_invalid_input);
- mPassword.setText("");
- }
- }
-
- if (v == mEmergencyCall) {
- mCallback.takeEmergencyCallAction();
- }
- }
-
- @Override
- public boolean dispatchKeyEvent(KeyEvent event) {
- if (event.getAction() == KeyEvent.ACTION_DOWN
- && event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
- mCallback.goToLockScreen();
- return true;
- }
- return super.dispatchKeyEvent(event);
- }
-
- private boolean checkPassword() {
- final String login = mLogin.getText().toString();
- final String password = mPassword.getText().toString();
- try {
- return mAccountsService.shouldUnlock(login, password);
- } catch (RemoteException e) {
- return false;
- }
- }
-
- /** {@inheritDoc} */
- public void onServiceConnected(ComponentName name, IBinder service) {
- Log.v("AccountUnlockScreen", "debug: About to grab as interface");
- mAccountsService = IAccountsService.Stub.asInterface(service);
- }
-
- /** {@inheritDoc} */
- public void onServiceDisconnected(ComponentName name) {
- mAccountsService = null;
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import com.android.internal.R;
-import com.google.android.collect.Lists;
-
-import android.app.AlertDialog;
-import android.app.StatusBarManager;
-import android.content.Context;
-import android.content.BroadcastReceiver;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.DialogInterface;
-import android.media.AudioManager;
-import android.os.LocalPowerManager;
-import android.os.Handler;
-import android.os.Message;
-import android.os.SystemClock;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.BaseAdapter;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import java.util.ArrayList;
-
-/**
- * Helper to show the global actions dialog. Each item is an {@link Action} that
- * may show depending on whether the keyguard is showing, and whether the device
- * is provisioned.
- */
-class GlobalActions implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener {
-
- private StatusBarManager mStatusBar;
-
- private final Context mContext;
- private final LocalPowerManager mPowerManager;
- private final AudioManager mAudioManager;
- private ArrayList<Action> mItems;
- private AlertDialog mDialog;
-
- private ToggleAction mSilentModeToggle;
-
- private MyAdapter mAdapter;
-
- private boolean mKeyguardShowing = false;
- private boolean mDeviceProvisioned = false;
-
- /**
- * @param context everything needs a context :)
- * @param powerManager used to turn the screen off (the lock action).
- */
- public GlobalActions(Context context, LocalPowerManager powerManager) {
- mContext = context;
- mPowerManager = powerManager;
- mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
-
- // receive broadcasts
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
- context.registerReceiver(mBroadcastReceiver, filter);
- }
-
- /**
- * Show the global actions dialog (creating if necessary)
- * @param keyguardShowing True if keyguard is showing
- */
- public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {
- mKeyguardShowing = keyguardShowing;
- mDeviceProvisioned = isDeviceProvisioned;
- if (mDialog == null) {
- mStatusBar = (StatusBarManager)mContext.getSystemService(Context.STATUS_BAR_SERVICE);
- mDialog = createDialog();
- }
- prepareDialog();
-
- mStatusBar.disable(StatusBarManager.DISABLE_EXPAND);
- mDialog.show();
- }
-
- /**
- * Create the global actions dialog.
- * @return A new dialog.
- */
- private AlertDialog createDialog() {
-
- mSilentModeToggle = new ToggleAction(
- R.drawable.ic_lock_silent_mode,
- R.drawable.ic_lock_silent_mode_off,
- R.string.global_action_toggle_silent_mode,
- R.string.global_action_silent_mode_on_status,
- R.string.global_action_silent_mode_off_status) {
-
- void onToggle(boolean on) {
- mAudioManager.setRingerMode(on ? AudioManager.RINGER_MODE_SILENT
- : AudioManager.RINGER_MODE_NORMAL);
- }
-
- public boolean showDuringKeyguard() {
- return true;
- }
-
- public boolean showBeforeProvisioning() {
- return false;
- }
- };
-
- mItems = Lists.newArrayList(
- /* Disabled pending bug 1304831 -- key or touch events wake up device before it
- * can go to sleep.
- // first: lock screen
- new SinglePressAction(com.android.internal.R.drawable.ic_lock_lock, R.string.global_action_lock) {
-
- public void onPress() {
- mPowerManager.goToSleep(SystemClock.uptimeMillis() + 1);
- }
-
- public boolean showDuringKeyguard() {
- return false;
- }
-
- public boolean showBeforeProvisioning() {
- return false;
- }
- },
- */
- // next: silent mode
- mSilentModeToggle,
- // last: power off
- new SinglePressAction(com.android.internal.R.drawable.ic_lock_power_off, R.string.global_action_power_off) {
-
- public void onPress() {
- // shutdown by making sure radio and power are handled accordingly.
- ShutdownThread.shutdownAfterDisablingRadio(mContext, true);
- }
-
- public boolean showDuringKeyguard() {
- return true;
- }
-
- public boolean showBeforeProvisioning() {
- return true;
- }
- });
-
- mAdapter = new MyAdapter();
-
- final AlertDialog.Builder ab = new AlertDialog.Builder(mContext);
-
- ab.setAdapter(mAdapter, this)
- .setInverseBackgroundForced(true)
- .setTitle(R.string.global_actions);
-
- final AlertDialog dialog = ab.create();
- dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
- dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
- WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
-
- dialog.setOnDismissListener(this);
-
- return dialog;
- }
-
- private void prepareDialog() {
- // TODO: May need another 'Vibrate' toggle button, but for now treat them the same
- final boolean silentModeOn =
- mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL;
- mSilentModeToggle.updateState(silentModeOn);
- mAdapter.notifyDataSetChanged();
- if (mKeyguardShowing) {
- mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
- } else {
- mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
- }
- }
-
- /** {@inheritDoc} */
- public void onDismiss(DialogInterface dialog) {
- mStatusBar.disable(StatusBarManager.DISABLE_NONE);
- }
-
- /** {@inheritDoc} */
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- mAdapter.getItem(which).onPress();
- }
-
-
- /**
- * The adapter used for the list within the global actions dialog, taking
- * into account whether the keyguard is showing via
- * {@link GlobalActions#mKeyguardShowing} and whether the device is provisioned
- * via {@link GlobalActions#mDeviceProvisioned}.
- */
- private class MyAdapter extends BaseAdapter {
-
- public int getCount() {
- int count = 0;
-
- for (int i = 0; i < mItems.size(); i++) {
- final Action action = mItems.get(i);
-
- if (mKeyguardShowing && !action.showDuringKeyguard()) {
- continue;
- }
- if (!mDeviceProvisioned && !action.showBeforeProvisioning()) {
- continue;
- }
- count++;
- }
- return count;
- }
-
- public Action getItem(int position) {
-
- int filteredPos = 0;
- for (int i = 0; i < mItems.size(); i++) {
- final Action action = mItems.get(i);
- if (mKeyguardShowing && !action.showDuringKeyguard()) {
- continue;
- }
- if (!mDeviceProvisioned && !action.showBeforeProvisioning()) {
- continue;
- }
- if (filteredPos == position) {
- return action;
- }
- filteredPos++;
- }
-
- throw new IllegalArgumentException("position " + position + " out of "
- + "range of showable actions, filtered count = "
- + "= " + getCount() + ", keyguardshowing=" + mKeyguardShowing
- + ", provisioned=" + mDeviceProvisioned);
- }
-
-
- public long getItemId(int position) {
- return position;
- }
-
- public View getView(int position, View convertView, ViewGroup parent) {
- Action action = getItem(position);
- return action.create(mContext, (LinearLayout) convertView, LayoutInflater.from(mContext));
- }
- }
-
- // note: the scheme below made more sense when we were planning on having
- // 8 different things in the global actions dialog. seems overkill with
- // only 3 items now, but may as well keep this flexible approach so it will
- // be easy should someone decide at the last minute to include something
- // else, such as 'enable wifi', or 'enable bluetooth'
-
- /**
- * What each item in the global actions dialog must be able to support.
- */
- private interface Action {
- LinearLayout create(Context context, LinearLayout convertView, LayoutInflater inflater);
-
- void onPress();
-
- /**
- * @return whether this action should appear in the dialog when the keygaurd
- * is showing.
- */
- boolean showDuringKeyguard();
-
- /**
- * @return whether this action should appear in the dialog before the
- * device is provisioned.
- */
- boolean showBeforeProvisioning();
- }
-
- /**
- * A single press action maintains no state, just responds to a press
- * and takes an action.
- */
- private static abstract class SinglePressAction implements Action {
- private final int mIconResId;
- private final int mMessageResId;
-
- protected SinglePressAction(int iconResId, int messageResId) {
- mIconResId = iconResId;
- mMessageResId = messageResId;
- }
-
- abstract public void onPress();
-
- public LinearLayout create(Context context, LinearLayout convertView, LayoutInflater inflater) {
- LinearLayout v = (LinearLayout) ((convertView != null) ?
- convertView :
- inflater.inflate(R.layout.global_actions_item, null));
-
- ImageView icon = (ImageView) v.findViewById(R.id.icon);
- TextView messageView = (TextView) v.findViewById(R.id.message);
-
- v.findViewById(R.id.status).setVisibility(View.GONE);
-
- icon.setImageDrawable(context.getResources().getDrawable(mIconResId));
- messageView.setText(mMessageResId);
-
- return v;
- }
- }
-
- /**
- * A toggle action knows whether it is on or off, and displays an icon
- * and status message accordingly.
- */
- static abstract class ToggleAction implements Action {
-
- private boolean mOn = false;
-
- // prefs
- private final int mEnabledIconResId;
- private final int mDisabledIconResid;
- private final int mMessageResId;
- private final int mEnabledStatusMessageResId;
- private final int mDisabledStatusMessageResId;
-
- /**
- * @param enabledIconResId The icon for when this action is on.
- * @param disabledIconResid The icon for when this action is off.
- * @param essage The general information message, e.g 'Silent Mode'
- * @param enabledStatusMessageResId The on status message, e.g 'sound disabled'
- * @param disabledStatusMessageResId The off status message, e.g. 'sound enabled'
- */
- public ToggleAction(int enabledIconResId,
- int disabledIconResid,
- int essage,
- int enabledStatusMessageResId,
- int disabledStatusMessageResId) {
- mEnabledIconResId = enabledIconResId;
- mDisabledIconResid = disabledIconResid;
- mMessageResId = essage;
- mEnabledStatusMessageResId = enabledStatusMessageResId;
- mDisabledStatusMessageResId = disabledStatusMessageResId;
- }
-
- public LinearLayout create(Context context, LinearLayout convertView,
- LayoutInflater inflater) {
- LinearLayout v = (LinearLayout) ((convertView != null) ?
- convertView :
- inflater.inflate(R
- .layout.global_actions_item, null));
-
- ImageView icon = (ImageView) v.findViewById(R.id.icon);
- TextView messageView = (TextView) v.findViewById(R.id.message);
- TextView statusView = (TextView) v.findViewById(R.id.status);
-
- messageView.setText(mMessageResId);
-
- icon.setImageDrawable(context.getResources().getDrawable(
- (mOn ? mEnabledIconResId : mDisabledIconResid)));
- statusView.setText(mOn ? mEnabledStatusMessageResId : mDisabledStatusMessageResId);
- statusView.setVisibility(View.VISIBLE);
-
- return v;
- }
-
- public void onPress() {
- updateState(!mOn);
- onToggle(mOn);
- }
-
- abstract void onToggle(boolean on);
-
- public void updateState(boolean on) {
- mOn = on;
- }
- }
-
- private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
- String reason = intent.getStringExtra(PhoneWindowManager.SYSTEM_DIALOG_REASON_KEY);
- if (! PhoneWindowManager.SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS.equals(reason)) {
- mHandler.sendEmptyMessage(MESSAGE_DISMISS);
- }
- }
- }
- };
-
- private static final int MESSAGE_DISMISS = 0;
- private Handler mHandler = new Handler() {
- public void handleMessage(Message msg) {
- if (msg.what == MESSAGE_DISMISS) {
- if (mDialog != null) {
- mDialog.dismiss();
- }
- }
- }
- };
-}
+++ /dev/null
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-/**
- * Common interface of each {@link android.view.View} that is a screen of
- * {@link LockPatternKeyguardView}.
- */
-public interface KeyguardScreen {
-
- /**
- * Return true if your view needs input, so should allow the soft
- * keyboard to be displayed.
- */
- boolean needsInput();
-
- /**
- * This screen is no longer in front of the user.
- */
- void onPause();
-
- /**
- * This screen is going to be in front of the user.
- */
- void onResume();
-
- /**
- * This view is going away; a hook to do cleanup.
- */
- void cleanUp();
-}
+++ /dev/null
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-/**
- * Within a keyguard, there may be several screens that need a callback
- * to the host keyguard view.
- */
-public interface KeyguardScreenCallback extends KeyguardViewCallback {
-
- /**
- * Transition to the lock screen.
- */
- void goToLockScreen();
-
- /**
- * Transitino to th unlock screen.
- */
- void goToUnlockScreen();
-
- /**
- * @return Whether the keyguard requires some sort of PIN.
- */
- boolean isSecure();
-
- /**
- * @return Whether we are in a mode where we only want to verify the
- * user can get past the keyguard.
- */
- boolean isVerifyUnlockOnly();
-
- /**
- * Stay on me, but recreate me (so I can use a different layout).
- */
- void recreateMe();
-
- /**
- * Take action to send an emergency call.
- */
- void takeEmergencyCallAction();
-
- /**
- * Report that the user had a failed attempt unlocking via the pattern.
- */
- void reportFailedPatternAttempt();
-
- /**
- * Report whether we there's another way to unlock the device.
- * @return true
- */
- boolean doesFallbackUnlockScreenExist();
-}
+++ /dev/null
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.Configuration;
-import android.database.ContentObserver;
-import static android.os.BatteryManager.BATTERY_STATUS_CHARGING;
-import static android.os.BatteryManager.BATTERY_STATUS_FULL;
-import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
-import android.os.Handler;
-import android.os.Message;
-import android.provider.Settings;
-import android.provider.Telephony;
-import static android.provider.Telephony.Intents.EXTRA_PLMN;
-import static android.provider.Telephony.Intents.EXTRA_SHOW_PLMN;
-import static android.provider.Telephony.Intents.EXTRA_SHOW_SPN;
-import static android.provider.Telephony.Intents.EXTRA_SPN;
-import static android.provider.Telephony.Intents.SPN_STRINGS_UPDATED_ACTION;
-import com.android.internal.telephony.SimCard;
-import com.android.internal.telephony.TelephonyIntents;
-import android.util.Log;
-import com.android.internal.R;
-import com.google.android.collect.Lists;
-
-import java.util.ArrayList;
-
-/**
- * Watches for updates that may be interesting to the keyguard, and provides
- * the up to date information as well as a registration for callbacks that care
- * to be updated.
- *
- * Note: under time crunch, this has been extended to include some stuff that
- * doesn't really belong here. see {@link #handleBatteryUpdate} where it shutdowns
- * the device, and {@link #getFailedAttempts()}, {@link #reportFailedAttempt()}
- * and {@link #clearFailedAttempts()}. Maybe we should rename this 'KeyguardContext'...
- */
-public class KeyguardUpdateMonitor {
-
- static private final String TAG = "KeyguardUpdateMonitor";
- static private final boolean DEBUG = false;
-
- private static final int LOW_BATTERY_THRESHOLD = 20;
-
- private final Context mContext;
-
- private SimCard.State mSimState = SimCard.State.READY;
- private boolean mInPortrait;
- private boolean mKeyboardOpen;
-
- private boolean mDevicePluggedIn;
-
- private boolean mDeviceProvisioned;
-
- private int mBatteryLevel;
-
- private CharSequence mTelephonyPlmn;
- private CharSequence mTelephonySpn;
-
- private int mFailedAttempts = 0;
-
- private Handler mHandler;
-
- private ArrayList<ConfigurationChangeCallback> mConfigurationChangeCallbacks
- = Lists.newArrayList();
- private ArrayList<InfoCallback> mInfoCallbacks = Lists.newArrayList();
- private ArrayList<SimStateCallback> mSimStateCallbacks = Lists.newArrayList();
- private ContentObserver mContentObserver;
-
-
- // messages for the handler
- private static final int MSG_CONFIGURATION_CHANGED = 300;
- private static final int MSG_TIME_UPDATE = 301;
- private static final int MSG_BATTERY_UPDATE = 302;
- private static final int MSG_CARRIER_INFO_UPDATE = 303;
- private static final int MSG_SIM_STATE_CHANGE = 304;
-
-
- /**
- * When we receive a {@link com.android.internal.telephony.TelephonyIntents#ACTION_SIM_STATE_CHANGED} broadcast, and
- * then pass a result via our handler to {@link KeyguardUpdateMonitor#handleSimStateChange},
- * we need a single object to pass to the handler. This class helps decode
- * the intent and provide a {@link SimCard.State} result.
- */
- private static class SimArgs {
-
- public final SimCard.State simState;
-
- private SimArgs(Intent intent) {
- if (!TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(intent.getAction())) {
- throw new IllegalArgumentException("only handles intent ACTION_SIM_STATE_CHANGED");
- }
- String stateExtra = intent.getStringExtra(SimCard.INTENT_KEY_SIM_STATE);
- if (SimCard.INTENT_VALUE_SIM_ABSENT.equals(stateExtra)) {
- this.simState = SimCard.State.ABSENT;
- } else if (SimCard.INTENT_VALUE_SIM_READY.equals(stateExtra)) {
- this.simState = SimCard.State.READY;
- } else if (SimCard.INTENT_VALUE_SIM_LOCKED.equals(stateExtra)) {
- final String lockedReason = intent
- .getStringExtra(SimCard.INTENT_KEY_LOCKED_REASON);
- if (SimCard.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
- this.simState = SimCard.State.PIN_REQUIRED;
- } else if (SimCard.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
- this.simState = SimCard.State.PUK_REQUIRED;
- } else {
- this.simState = SimCard.State.UNKNOWN;
- }
- } else if (SimCard.INTENT_VALUE_LOCKED_NETWORK.equals(stateExtra)) {
- this.simState = SimCard.State.NETWORK_LOCKED;
- } else {
- this.simState = SimCard.State.UNKNOWN;
- }
- }
-
- public String toString() {
- return simState.toString();
- }
- }
-
- public KeyguardUpdateMonitor(Context context) {
- mContext = context;
-
- mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_CONFIGURATION_CHANGED:
- handleConfigurationChange();
- break;
- case MSG_TIME_UPDATE:
- handleTimeUpdate();
- break;
- case MSG_BATTERY_UPDATE:
- handleBatteryUpdate(msg.arg1, msg.arg2);
- break;
- case MSG_CARRIER_INFO_UPDATE:
- handleCarrierInfoUpdate();
- break;
- case MSG_SIM_STATE_CHANGE:
- handleSimStateChange((SimArgs) msg.obj);
- break;
- }
- }
- };
-
- mDeviceProvisioned = Settings.Secure.getInt(
- mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0;
-
- // Since device can't be un-provisioned, we only need to register a content observer
- // to update mDeviceProvisioned when we are...
- if (!mDeviceProvisioned) {
- mContentObserver = new ContentObserver(mHandler) {
- @Override
- public void onChange(boolean selfChange) {
- super.onChange(selfChange);
- mDeviceProvisioned = Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.DEVICE_PROVISIONED, 0) != 0;
- if (mDeviceProvisioned && mContentObserver != null) {
- // We don't need the observer anymore...
- mContext.getContentResolver().unregisterContentObserver(mContentObserver);
- mContentObserver = null;
- }
- if (DEBUG) Log.d(TAG, "DEVICE_PROVISIONED state = " + mDeviceProvisioned);
- }
- };
-
- mContext.getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.DEVICE_PROVISIONED),
- false, mContentObserver);
-
- // prevent a race condition between where we check the flag and where we register the
- // observer by grabbing the value once again...
- mDeviceProvisioned = Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.DEVICE_PROVISIONED, 0) != 0;
- }
-
- mInPortrait = queryInPortrait();
- mKeyboardOpen = queryKeyboardOpen();
-
- // take a guess to start
- mSimState = SimCard.State.READY;
- mDevicePluggedIn = true;
- mBatteryLevel = 100;
-
- mTelephonyPlmn = getDefaultPlmn();
-
- // setup receiver
- final IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
- filter.addAction(Intent.ACTION_TIME_TICK);
- filter.addAction(Intent.ACTION_TIME_CHANGED);
- filter.addAction(Intent.ACTION_BATTERY_CHANGED);
- filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
- filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
- filter.addAction(SPN_STRINGS_UPDATED_ACTION);
- context.registerReceiver(new BroadcastReceiver() {
-
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (DEBUG) Log.d(TAG, "received broadcast " + action);
-
- if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
- mHandler.sendMessage(mHandler.obtainMessage(MSG_CONFIGURATION_CHANGED));
- } else if (Intent.ACTION_TIME_TICK.equals(action)
- || Intent.ACTION_TIME_CHANGED.equals(action)
- || Intent.ACTION_TIMEZONE_CHANGED.equals(action)) {
- mHandler.sendMessage(mHandler.obtainMessage(MSG_TIME_UPDATE));
- } else if (SPN_STRINGS_UPDATED_ACTION.equals(action)) {
- mTelephonyPlmn = getTelephonyPlmnFrom(intent);
- mTelephonySpn = getTelephonySpnFrom(intent);
- mHandler.sendMessage(mHandler.obtainMessage(MSG_CARRIER_INFO_UPDATE));
- } else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
- final int pluggedInStatus = intent
- .getIntExtra("status", BATTERY_STATUS_UNKNOWN);
- int batteryLevel = intent.getIntExtra("level", 0);
- final Message msg = mHandler.obtainMessage(
- MSG_BATTERY_UPDATE,
- pluggedInStatus,
- batteryLevel);
- mHandler.sendMessage(msg);
- } else if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)){
- mHandler.sendMessage(mHandler.obtainMessage(
- MSG_SIM_STATE_CHANGE,
- new SimArgs(intent)));
- }
- }
- }, filter);
- }
-
- /**
- * Handle {@link #MSG_CONFIGURATION_CHANGED}
- */
- private void handleConfigurationChange() {
- if (DEBUG) Log.d(TAG, "handleConfigurationChange");
-
- final boolean inPortrait = queryInPortrait();
- if (mInPortrait != inPortrait) {
- mInPortrait = inPortrait;
- for (int i = 0; i < mConfigurationChangeCallbacks.size(); i++) {
- mConfigurationChangeCallbacks.get(i).onOrientationChange(inPortrait);
- }
- }
-
- final boolean keyboardOpen = queryKeyboardOpen();
- if (mKeyboardOpen != keyboardOpen) {
- mKeyboardOpen = keyboardOpen;
- for (int i = 0; i < mConfigurationChangeCallbacks.size(); i++) {
- mConfigurationChangeCallbacks.get(i).onKeyboardChange(keyboardOpen);
- }
- }
- }
-
- /**
- * Handle {@link #MSG_TIME_UPDATE}
- */
- private void handleTimeUpdate() {
- if (DEBUG) Log.d(TAG, "handleTimeUpdate");
- for (int i = 0; i < mInfoCallbacks.size(); i++) {
- mInfoCallbacks.get(i).onTimeChanged();
- }
- }
-
- /**
- * Handle {@link #MSG_BATTERY_UPDATE}
- */
- private void handleBatteryUpdate(int pluggedInStatus, int batteryLevel) {
- if (DEBUG) Log.d(TAG, "handleBatteryUpdate");
- final boolean pluggedIn = isPluggedIn(pluggedInStatus);
-
- if (isBatteryUpdateInteresting(pluggedIn, batteryLevel)) {
- mBatteryLevel = batteryLevel;
- mDevicePluggedIn = pluggedIn;
- for (int i = 0; i < mInfoCallbacks.size(); i++) {
- mInfoCallbacks.get(i).onRefreshBatteryInfo(
- shouldShowBatteryInfo(), pluggedIn, batteryLevel);
- }
- }
-
- // shut down gracefully if our battery is critically low and we are not powered
- if (batteryLevel == 0 &&
- pluggedInStatus != BATTERY_STATUS_CHARGING &&
- pluggedInStatus != BATTERY_STATUS_UNKNOWN) {
- ShutdownThread.shutdownAfterDisablingRadio(mContext, false);
- }
- }
-
- /**
- * Handle {@link #MSG_CARRIER_INFO_UPDATE}
- */
- private void handleCarrierInfoUpdate() {
- if (DEBUG) Log.d(TAG, "handleCarrierInfoUpdate: plmn = " + mTelephonyPlmn
- + ", spn = " + mTelephonySpn);
-
- for (int i = 0; i < mInfoCallbacks.size(); i++) {
- mInfoCallbacks.get(i).onRefreshCarrierInfo(mTelephonyPlmn, mTelephonySpn);
- }
- }
-
- /**
- * Handle {@link #MSG_SIM_STATE_CHANGE}
- */
- private void handleSimStateChange(SimArgs simArgs) {
- final SimCard.State state = simArgs.simState;
-
- if (DEBUG) {
- Log.d(TAG, "handleSimStateChange: intentValue = " + simArgs + " "
- + "state resolved to " + state.toString());
- }
-
- if (state != SimCard.State.UNKNOWN && state != mSimState) {
- mSimState = state;
- for (int i = 0; i < mSimStateCallbacks.size(); i++) {
- mSimStateCallbacks.get(i).onSimStateChanged(state);
- }
- }
- }
-
- /**
- * @param status One of the statuses of {@link android.os.BatteryManager}
- * @return Whether the status maps to a status for being plugged in.
- */
- private boolean isPluggedIn(int status) {
- return status == BATTERY_STATUS_CHARGING || status == BATTERY_STATUS_FULL;
- }
-
- private boolean isBatteryUpdateInteresting(boolean pluggedIn, int batteryLevel) {
- // change in plug is always interesting
- if (mDevicePluggedIn != pluggedIn) {
- return true;
- }
-
- // change in battery level while plugged in
- if (pluggedIn && mBatteryLevel != batteryLevel) {
- return true;
- }
-
- if (!pluggedIn) {
- // not plugged in and going below threshold
- if (batteryLevel < LOW_BATTERY_THRESHOLD
- && mBatteryLevel >= LOW_BATTERY_THRESHOLD) {
- return true;
- }
- // not plugged in and going above threshold (sounds impossible, but, meh...)
- if (mBatteryLevel < LOW_BATTERY_THRESHOLD
- && batteryLevel >= LOW_BATTERY_THRESHOLD) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * What is the current orientation?
- */
- boolean queryInPortrait() {
- final Configuration configuration = mContext.getResources().getConfiguration();
- return configuration.orientation == Configuration.ORIENTATION_PORTRAIT;
- }
-
- /**
- * Is the (hard) keyboard currently open?
- */
- boolean queryKeyboardOpen() {
- final Configuration configuration = mContext.getResources().getConfiguration();
-
- return configuration.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO;
- }
-
- /**
- * @param intent The intent with action {@link Telephony.Intents#SPN_STRINGS_UPDATED_ACTION}
- * @return The string to use for the plmn, or null if it should not be shown.
- */
- private CharSequence getTelephonyPlmnFrom(Intent intent) {
- if (intent.getBooleanExtra(EXTRA_SHOW_PLMN, false)) {
- final String plmn = intent.getStringExtra(EXTRA_PLMN);
- if (plmn != null) {
- return plmn;
- } else {
- return getDefaultPlmn();
- }
- }
- return null;
- }
-
- /**
- * @return The default plmn (no service)
- */
- private CharSequence getDefaultPlmn() {
- return mContext.getResources().getText(
- R.string.lockscreen_carrier_default);
- }
-
- /**
- * @param intent The intent with action {@link Telephony.Intents#SPN_STRINGS_UPDATED_ACTION}
- * @return The string to use for the plmn, or null if it should not be shown.
- */
- private CharSequence getTelephonySpnFrom(Intent intent) {
- if (intent.getBooleanExtra(EXTRA_SHOW_SPN, false)) {
- final String spn = intent.getStringExtra(EXTRA_SPN);
- if (spn != null) {
- return spn;
- }
- }
- return null;
- }
-
- /**
- * Remove the given observer from being registered from any of the kinds
- * of callbacks.
- * @param observer The observer to remove (an instance of {@link ConfigurationChangeCallback},
- * {@link InfoCallback} or {@link SimStateCallback}
- */
- public void removeCallback(Object observer) {
- mConfigurationChangeCallbacks.remove(observer);
- mInfoCallbacks.remove(observer);
- mSimStateCallbacks.remove(observer);
- }
-
- /**
- * Callback for configuration changes.
- */
- interface ConfigurationChangeCallback {
- void onOrientationChange(boolean inPortrait);
-
- void onKeyboardChange(boolean isKeyboardOpen);
- }
-
- /**
- * Callback for general information releveant to lock screen.
- */
- interface InfoCallback {
- void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel);
- void onTimeChanged();
-
- /**
- * @param plmn The operator name of the registered network. May be null if it shouldn't
- * be displayed.
- * @param spn The service provider name. May be null if it shouldn't be displayed.
- */
- void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn);
- }
-
- /**
- * Callback to notify of sim state change.
- */
- interface SimStateCallback {
- void onSimStateChanged(SimCard.State simState);
- }
-
- /**
- * Register to receive notifications about configuration changes.
- * @param callback The callback.
- */
- public void registerConfigurationChangeCallback(ConfigurationChangeCallback callback) {
- mConfigurationChangeCallbacks.add(callback);
- }
-
- /**
- * Register to receive notifications about general keyguard information
- * (see {@link InfoCallback}.
- * @param callback The callback.
- */
- public void registerInfoCallback(InfoCallback callback) {
- mInfoCallbacks.add(callback);
- }
-
- /**
- * Register to be notified of sim state changes.
- * @param callback The callback.
- */
- public void registerSimStateCallback(SimStateCallback callback) {
- mSimStateCallbacks.add(callback);
- }
-
- public SimCard.State getSimState() {
- return mSimState;
- }
-
- /**
- * Report that the user succesfully entered the sim pin so we
- * have the information earlier than waiting for the intent
- * broadcast from the telephony code.
- */
- public void reportSimPinUnlocked() {
- mSimState = SimCard.State.READY;
- }
-
- public boolean isInPortrait() {
- return mInPortrait;
- }
-
- public boolean isKeyboardOpen() {
- return mKeyboardOpen;
- }
-
- public boolean isDevicePluggedIn() {
- return mDevicePluggedIn;
- }
-
- public int getBatteryLevel() {
- return mBatteryLevel;
- }
-
- public boolean shouldShowBatteryInfo() {
- return mDevicePluggedIn || mBatteryLevel < LOW_BATTERY_THRESHOLD;
- }
-
- public CharSequence getTelephonyPlmn() {
- return mTelephonyPlmn;
- }
-
- public CharSequence getTelephonySpn() {
- return mTelephonySpn;
- }
-
- /**
- * @return Whether the device is provisioned (whether they have gone through
- * the setup wizard)
- */
- public boolean isDeviceProvisioned() {
- return mDeviceProvisioned;
- }
-
- public int getFailedAttempts() {
- return mFailedAttempts;
- }
-
- public void clearFailedAttempts() {
- mFailedAttempts = 0;
- }
-
- public void reportFailedAttempt() {
- mFailedAttempts++;
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import android.content.Context;
-import android.content.Intent;
-import android.media.AudioManager;
-import android.view.KeyEvent;
-import android.view.View;
-import android.widget.FrameLayout;
-
-/**
- * Base class for keyguard views. {@link #reset} is where you should
- * reset the state of your view. Use the {@link KeyguardViewCallback} via
- * {@link #getCallback()} to send information back (such as poking the wake lock,
- * or finishing the keyguard).
- *
- * Handles intercepting of media keys that still work when the keyguard is
- * showing.
- */
-public abstract class KeyguardViewBase extends FrameLayout {
-
- private KeyguardViewCallback mCallback;
- private AudioManager mAudioManager;
-
- public KeyguardViewBase(Context context) {
- super(context);
- }
-
- // used to inject callback
- void setCallback(KeyguardViewCallback callback) {
- mCallback = callback;
- }
-
- public KeyguardViewCallback getCallback() {
- return mCallback;
- }
-
- /**
- * Called when you need to reset the state of your view.
- */
- abstract public void reset();
-
- /**
- * Called when the screen turned off.
- */
- abstract public void onScreenTurnedOff();
-
- /**
- * Called when the screen turned on.
- */
- abstract public void onScreenTurnedOn();
-
- /**
- * Called when a key has woken the device to give us a chance to adjust our
- * state according the the key. We are responsible for waking the device
- * (by poking the wake lock) once we are ready.
- *
- * The 'Tq' suffix is per the documentation in {@link android.view.WindowManagerPolicy}.
- * Be sure not to take any action that takes a long time; any significant
- * action should be posted to a handler.
- *
- * @param keyCode The wake key, which may be relevant for configuring the
- * keyguard.
- */
- abstract public void wakeWhenReadyTq(int keyCode);
-
- /**
- * Verify that the user can get past the keyguard securely. This is called,
- * for example, when the phone disables the keyguard but then wants to launch
- * something else that requires secure access.
- *
- * The result will be propogated back via {@link KeyguardViewCallback#keyguardDone(boolean)}
- */
- abstract public void verifyUnlock();
-
- /**
- * Called before this view is being removed.
- */
- abstract public void cleanUp();
-
- @Override
- public boolean dispatchKeyEvent(KeyEvent event) {
- if (shouldEventKeepScreenOnWhileKeyguardShowing(event)) {
- mCallback.pokeWakelock();
- }
-
- if (interceptMediaKey(event)) {
- return true;
- }
- return super.dispatchKeyEvent(event);
- }
-
- private boolean shouldEventKeepScreenOnWhileKeyguardShowing(KeyEvent event) {
- if (event.getAction() != KeyEvent.ACTION_DOWN) {
- return false;
- }
- switch (event.getKeyCode()) {
- case KeyEvent.KEYCODE_DPAD_DOWN:
- case KeyEvent.KEYCODE_DPAD_LEFT:
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- case KeyEvent.KEYCODE_DPAD_UP:
- return false;
- default:
- return true;
- }
- }
-
- /**
- * Allows the media keys to work when the keygaurd is showing.
- * The media keys should be of no interest to the actualy keygaurd view(s),
- * so intercepting them here should not be of any harm.
- * @param event The key event
- * @return whether the event was consumed as a media key.
- */
- private boolean interceptMediaKey(KeyEvent event) {
- final int keyCode = event.getKeyCode();
- if (event.getAction() == KeyEvent.ACTION_DOWN) {
- switch (keyCode) {
- 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);
- getContext().sendOrderedBroadcast(intent, null);
- return true;
- }
-
- case KeyEvent.KEYCODE_VOLUME_UP:
- case KeyEvent.KEYCODE_VOLUME_DOWN: {
- synchronized (this) {
- if (mAudioManager == null) {
- mAudioManager = (AudioManager) getContext().getSystemService(
- Context.AUDIO_SERVICE);
- }
- }
- // Volume buttons should only function for music.
- if (mAudioManager.isMusicActive()) {
- mAudioManager.adjustStreamVolume(
- AudioManager.STREAM_MUSIC,
- keyCode == KeyEvent.KEYCODE_VOLUME_UP
- ? AudioManager.ADJUST_RAISE
- : AudioManager.ADJUST_LOWER,
- 0);
- }
- // Don't execute default volume behavior
- return true;
- }
- }
- } else if (event.getAction() == KeyEvent.ACTION_UP) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_MUTE:
- 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);
- getContext().sendOrderedBroadcast(intent, null);
- return true;
- }
- }
- }
- return false;
- }
-
-}
+++ /dev/null
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-/**
- * The callback used by the keyguard view to tell the {@link KeyguardViewMediator}
- * various things.
- */
-public interface KeyguardViewCallback {
-
- /**
- * Request the wakelock to be poked for the default amount of time.
- */
- void pokeWakelock();
-
- /**
- * Request the wakelock to be poked for a specific amount of time.
- * @param millis The amount of time in millis.
- */
- void pokeWakelock(int millis);
-
- /**
- * Report that the keyguard is done.
- * @param authenticated Whether the user securely got past the keyguard.
- * the only reason for this to be false is if the keyguard was instructed
- * to appear temporarily to verify the user is supposed to get past the
- * keyguard, and the user fails to do so.
- */
- void keyguardDone(boolean authenticated);
-
- /**
- * Report that the keyguard is done drawing.
- */
- void keyguardDoneDrawing();
-}
+++ /dev/null
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import com.android.internal.R;
-
-import android.content.Context;
-import android.content.pm.ActivityInfo;
-import android.graphics.PixelFormat;
-import android.graphics.Canvas;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewManager;
-import android.view.WindowManager;
-import android.widget.FrameLayout;
-
-/**
- * Manages creating, showing, hiding and resetting the keyguard. Calls back
- * via {@link com.android.internal.policy.impl.KeyguardViewCallback} to poke
- * the wake lock and report that the keyguard is done, which is in turn,
- * reported to this class by the current {@link KeyguardViewBase}.
- */
-public class KeyguardViewManager implements KeyguardWindowController {
- private final static boolean DEBUG = false;
- private static String TAG = "KeyguardViewManager";
-
- private final Context mContext;
- private final ViewManager mViewManager;
- private final KeyguardViewCallback mCallback;
- private final KeyguardViewProperties mKeyguardViewProperties;
-
- private final KeyguardUpdateMonitor mUpdateMonitor;
-
- private WindowManager.LayoutParams mWindowLayoutParams;
- private boolean mNeedsInput = false;
-
- private FrameLayout mKeyguardHost;
- private KeyguardViewBase mKeyguardView;
-
- private boolean mScreenOn = false;
-
- /**
- * @param context Used to create views.
- * @param viewManager Keyguard will be attached to this.
- * @param callback Used to notify of changes.
- */
- public KeyguardViewManager(Context context, ViewManager viewManager,
- KeyguardViewCallback callback, KeyguardViewProperties keyguardViewProperties, KeyguardUpdateMonitor updateMonitor) {
- mContext = context;
- mViewManager = viewManager;
- mCallback = callback;
- mKeyguardViewProperties = keyguardViewProperties;
-
- mUpdateMonitor = updateMonitor;
- }
-
- /**
- * Helper class to host the keyguard view.
- */
- private static class KeyguardViewHost extends FrameLayout {
- private final KeyguardViewCallback mCallback;
-
- private KeyguardViewHost(Context context, KeyguardViewCallback callback) {
- super(context);
- mCallback = callback;
- }
-
- @Override
- protected void dispatchDraw(Canvas canvas) {
- super.dispatchDraw(canvas);
- mCallback.keyguardDoneDrawing();
- }
- }
-
- /**
- * Show the keyguard. Will handle creating and attaching to the view manager
- * lazily.
- */
- public synchronized void show() {
- if (DEBUG) Log.d(TAG, "show()");
-
- if (mKeyguardHost == null) {
- if (DEBUG) Log.d(TAG, "keyguard host is null, creating it...");
-
- mKeyguardHost = new KeyguardViewHost(mContext, mCallback);
-
- final int stretch = ViewGroup.LayoutParams.FILL_PARENT;
- int flags = WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN
- /*| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
- | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR*/ ;
- if (!mNeedsInput) {
- flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
- }
- WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- stretch, stretch, WindowManager.LayoutParams.TYPE_KEYGUARD,
- flags, PixelFormat.OPAQUE);
- lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
- lp.windowAnimations = com.android.internal.R.style.Animation_LockScreen;
- lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
- lp.setTitle("Keyguard");
- mWindowLayoutParams = lp;
-
- mViewManager.addView(mKeyguardHost, lp);
- }
-
- if (mKeyguardView == null) {
- if (DEBUG) Log.d(TAG, "keyguard view is null, creating it...");
- mKeyguardView = mKeyguardViewProperties.createKeyguardView(mContext, mUpdateMonitor, this);
- mKeyguardView.setId(R.id.lock_screen);
- mKeyguardView.setCallback(mCallback);
-
- final ViewGroup.LayoutParams lp = new FrameLayout.LayoutParams(
- ViewGroup.LayoutParams.FILL_PARENT,
- ViewGroup.LayoutParams.FILL_PARENT);
-
- mKeyguardHost.addView(mKeyguardView, lp);
-
- if (mScreenOn) {
- mKeyguardView.onScreenTurnedOn();
- }
- }
-
- mKeyguardHost.setVisibility(View.VISIBLE);
- mKeyguardView.requestFocus();
- }
-
- public void setNeedsInput(boolean needsInput) {
- mNeedsInput = needsInput;
- if (mWindowLayoutParams != null) {
- if (needsInput) {
- mWindowLayoutParams.flags &=
- ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
- } else {
- mWindowLayoutParams.flags |=
- WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
- }
- mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
- }
- }
-
- /**
- * Reset the state of the view.
- */
- public synchronized void reset() {
- if (DEBUG) Log.d(TAG, "reset()");
- if (mKeyguardView != null) {
- mKeyguardView.reset();
- }
- }
-
- public synchronized void onScreenTurnedOff() {
- if (DEBUG) Log.d(TAG, "onScreenTurnedOff()");
- mScreenOn = false;
- if (mKeyguardView != null) {
- mKeyguardView.onScreenTurnedOff();
- }
- }
-
- public synchronized void onScreenTurnedOn() {
- if (DEBUG) Log.d(TAG, "onScreenTurnedOn()");
- mScreenOn = true;
- if (mKeyguardView != null) {
- mKeyguardView.onScreenTurnedOn();
- }
- }
-
- public synchronized void verifyUnlock() {
- if (DEBUG) Log.d(TAG, "verifyUnlock()");
- show();
- mKeyguardView.verifyUnlock();
- }
-
- /**
- * A key has woken the device. We use this to potentially adjust the state
- * of the lock screen based on the key.
- *
- * The 'Tq' suffix is per the documentation in {@link android.view.WindowManagerPolicy}.
- * Be sure not to take any action that takes a long time; any significant
- * action should be posted to a handler.
- *
- * @param keyCode The wake key.
- */
- public void wakeWhenReadyTq(int keyCode) {
- if (DEBUG) Log.d(TAG, "wakeWhenReady(" + keyCode + ")");
- if (mKeyguardView != null) {
- mKeyguardView.wakeWhenReadyTq(keyCode);
- }
- }
-
- /**
- * Hides the keyguard view
- */
- public synchronized void hide() {
- if (DEBUG) Log.d(TAG, "hide()");
- if (mKeyguardHost != null) {
- mKeyguardHost.setVisibility(View.GONE);
- if (mKeyguardView != null) {
- mKeyguardHost.removeView(mKeyguardView);
- mKeyguardView.cleanUp();
- mKeyguardView = null;
- }
- }
- }
-
- /**
- * @return Whether the keyguard is showing
- */
- public synchronized boolean isShowing() {
- return (mKeyguardHost != null && mKeyguardHost.getVisibility() == View.VISIBLE);
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.app.StatusBarManager;
-import static android.app.StatusBarManager.DISABLE_NONE;
-import static android.app.StatusBarManager.DISABLE_EXPAND;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Handler;
-import android.os.LocalPowerManager;
-import android.os.Message;
-import android.os.PowerManager;
-import android.os.SystemClock;
-import android.util.Config;
-import android.util.Log;
-import android.util.EventLog;
-import android.view.KeyEvent;
-import android.view.WindowManagerImpl;
-import android.view.WindowManagerPolicy;
-import com.android.internal.telephony.SimCard;
-import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.widget.LockPatternUtils;
-
-/**
- * Mediates requests related to the keyguard. This includes queries about the
- * state of the keyguard, power management events that effect whether the keyguard
- * should be shown or reset, callbacks to the phone window manager to notify
- * it of when the keyguard is showing, and events from the keyguard view itself
- * stating that the keyguard was succesfully unlocked.
- *
- * Note that the keyguard view is shown when the screen is off (as appropriate)
- * so that once the screen comes on, it will be ready immediately.
- *
- * Example queries about the keyguard:
- * - is {movement, key} one that should wake the keygaurd?
- * - is the keyguard showing?
- * - are input events restricted due to the state of the keyguard?
- *
- * Callbacks to the phone window manager:
- * - the keyguard is showing
- *
- * Example external events that translate to keyguard view changes:
- * - screen turned off -> reset the keyguard, and show it so it will be ready
- * next time the screen turns on
- * - keyboard is slid open -> if the keyguard is not secure, hide it
- *
- * Events from the keyguard view:
- * - user succesfully unlocked keyguard -> hide keyguard view, and no longer
- * restrict input events.
- *
- * Note: in addition to normal power managment events that effect the state of
- * whether the keyguard should be showing, external apps and services may request
- * that the keyguard be disabled via {@link #setKeyguardEnabled(boolean)}. When
- * false, this will override all other conditions for turning on the keyguard.
- *
- * Threading and synchronization:
- * This class is created by the initialization routine of the {@link WindowManagerPolicy},
- * and runs on its thread. The keyguard UI is created from that thread in the
- * constructor of this class. The apis may be called from other threads, including the
- * {@link com.android.server.KeyInputQueue}'s and {@link android.view.WindowManager}'s.
- * Therefore, methods on this class are synchronized, and any action that is pointed
- * directly to the keyguard UI is posted to a {@link Handler} to ensure it is taken on the UI
- * thread of the keyguard.
- */
-public class KeyguardViewMediator implements KeyguardViewCallback,
- KeyguardUpdateMonitor.ConfigurationChangeCallback, KeyguardUpdateMonitor.SimStateCallback {
- private final static boolean DEBUG = false && Config.LOGD;
- private final static boolean DBG_WAKE = DEBUG || true;
-
- private final static String TAG = "KeyguardViewMediator";
-
- private static final String DELAYED_KEYGUARD_ACTION = "com.android.internal.policy.impl.PhoneWindowManager.DELAYED_KEYGUARD";
-
- // used for handler messages
- private static final int TIMEOUT = 1;
- private static final int SHOW = 2;
- private static final int HIDE = 3;
- private static final int RESET = 4;
- private static final int VERIFY_UNLOCK = 5;
- private static final int NOTIFY_SCREEN_OFF = 6;
- private static final int NOTIFY_SCREEN_ON = 7;
- private static final int WAKE_WHEN_READY = 8;
- private static final int KEYGUARD_DONE = 9;
- private static final int KEYGUARD_DONE_DRAWING = 10;
-
- /**
- * The default amount of time we stay awake (used for all key input)
- */
- protected static final int AWAKE_INTERVAL_DEFAULT_MS = 5000;
-
-
- /**
- * The default amount of time we stay awake (used for all key input) when
- * the keyboard is open
- */
- protected static final int AWAKE_INTERVAL_DEFAULT_KEYBOARD_OPEN_MS = 10000;
-
- /**
- * How long to wait after the screen turns off due to timeout before
- * turning on the keyguard (i.e, the user has this much time to turn
- * the screen back on without having to face the keyguard).
- */
- private static final int KEYGUARD_DELAY_MS = 0;
-
- /**
- * How long we'll wait for the {@link KeyguardViewCallback#keyguardDoneDrawing()}
- * callback before unblocking a call to {@link #setKeyguardEnabled(boolean)}
- * that is reenabling the keyguard.
- */
- private static final int KEYGUARD_DONE_DRAWING_TIMEOUT_MS = 2000;
-
- private Context mContext;
- private AlarmManager mAlarmManager;
-
- private boolean mSystemReady;
-
- /** Low level access to the power manager for enableUserActivity. Having this
- * requires that we run in the system process. */
- LocalPowerManager mRealPowerManager;
-
- /** High level access to the power manager for WakeLocks */
- private PowerManager mPM;
-
- /**
- * Used to keep the device awake while the keyguard is showing, i.e for
- * calls to {@link #pokeWakelock()}
- */
- private PowerManager.WakeLock mWakeLock;
-
- /**
- * Does not turn on screen, held while a call to {@link KeyguardViewManager#wakeWhenReadyTq(int)}
- * is called to make sure the device doesn't sleep before it has a chance to poke
- * the wake lock.
- * @see #wakeWhenReadyLocked(int)
- */
- private PowerManager.WakeLock mWakeAndHandOff;
-
- /**
- * Used to disable / reenable status bar expansion.
- */
- private StatusBarManager mStatusBarManager;
-
- private KeyguardViewManager mKeyguardViewManager;
-
- // these are protected by synchronized (this)
-
- /**
- * External apps (like the phone app) can tell us to disable the keygaurd.
- */
- private boolean mExternallyEnabled = true;
-
- /**
- * Remember if an external call to {@link #setKeyguardEnabled} with value
- * false caused us to hide the keyguard, so that we need to reshow it once
- * the keygaurd is reenabled with another call with value true.
- */
- private boolean mNeedToReshowWhenReenabled = false;
-
- // cached value of whether we are showing (need to know this to quickly
- // answer whether the input should be restricted)
- private boolean mShowing = false;
-
- /**
- * Helps remember whether the screen has turned on since the last time
- * it turned off due to timeout. see {@link #onScreenTurnedOff(int)}
- */
- private int mDelayedShowingSequence;
-
- private int mWakelockSequence;
-
- private PhoneWindowManager mCallback;
-
- /**
- * If the user has disabled the keyguard, then requests to exit, this is
- * how we'll ultimately let them know whether it was successful. We use this
- * var being non-null as an indicator that there is an in progress request.
- */
- private WindowManagerPolicy.OnKeyguardExitResult mExitSecureCallback;
-
- // the properties of the keyguard
- private KeyguardViewProperties mKeyguardViewProperties;
-
- private KeyguardUpdateMonitor mUpdateMonitor;
-
- private boolean mKeyboardOpen = false;
-
- /**
- * {@link #setKeyguardEnabled} waits on this condition when it reenables
- * the keyguard.
- */
- private boolean mWaitingUntilKeyguardVisible = false;
-
- public KeyguardViewMediator(Context context, PhoneWindowManager callback,
- LocalPowerManager powerManager) {
- mContext = context;
-
- mRealPowerManager = powerManager;
- mPM = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- mWakeLock = mPM.newWakeLock(
- PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP,
- "keyguard");
- mWakeLock.setReferenceCounted(false);
-
- mWakeAndHandOff = mPM.newWakeLock(
- PowerManager.PARTIAL_WAKE_LOCK,
- "keyguardWakeAndHandOff");
- mWakeAndHandOff.setReferenceCounted(false);
-
- IntentFilter filter = new IntentFilter();
- filter.addAction(DELAYED_KEYGUARD_ACTION);
- filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
- filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
- context.registerReceiver(mBroadCastReceiver, filter);
- mAlarmManager = (AlarmManager) context
- .getSystemService(Context.ALARM_SERVICE);
- mCallback = callback;
-
- mUpdateMonitor = new KeyguardUpdateMonitor(context);
-
- mUpdateMonitor.registerConfigurationChangeCallback(this);
- mUpdateMonitor.registerSimStateCallback(this);
-
- mKeyguardViewProperties =
- new LockPatternKeyguardViewProperties(
- new LockPatternUtils(mContext.getContentResolver()),
- mUpdateMonitor);
-
- mKeyguardViewManager = new KeyguardViewManager(
- context, WindowManagerImpl.getDefault(), this,
- mKeyguardViewProperties, mUpdateMonitor);
-
- }
-
- /**
- * Let us know that the system is ready after startup.
- */
- public void onSystemReady() {
- synchronized (this) {
- if (DEBUG) Log.d(TAG, "onSystemReady");
- mSystemReady = true;
- doKeyguard();
- }
- }
-
- /**
- * Called to let us know the screen was turned off.
- * @param why either {@link WindowManagerPolicy#OFF_BECAUSE_OF_USER} or
- * {@link WindowManagerPolicy#OFF_BECAUSE_OF_TIMEOUT}.
- */
- public void onScreenTurnedOff(int why) {
- synchronized (this) {
- if (DEBUG) Log.d(TAG, "onScreenTurnedOff(" + why + ")");
-
- if (mExitSecureCallback != null) {
- if (DEBUG) Log.d(TAG, "pending exit secure callback cancelled");
- mExitSecureCallback.onKeyguardExitResult(false);
- mExitSecureCallback = null;
- if (!mExternallyEnabled) {
- hideLocked();
- }
- } else if (mShowing) {
- notifyScreenOffLocked();
- resetStateLocked();
- } else if (why == WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT) {
- // if the screen turned off because of timeout, set an alarm
- // to enable it a little bit later (i.e, give the user a chance
- // to turn the screen back on within a certain window without
- // having to unlock the screen)
- long when = SystemClock.elapsedRealtime() + KEYGUARD_DELAY_MS;
- Intent intent = new Intent(DELAYED_KEYGUARD_ACTION);
- intent.putExtra("seq", mDelayedShowingSequence);
- PendingIntent sender = PendingIntent.getBroadcast(mContext,
- 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, when,
- sender);
- if (DEBUG) Log.d(TAG, "setting alarm to turn off keyguard, seq = " + mDelayedShowingSequence);
- } else {
- doKeyguard();
- }
- }
- }
-
- /**
- * Let's us know the screen was turned on.
- */
- public void onScreenTurnedOn() {
- synchronized (this) {
- mDelayedShowingSequence++;
- if (DEBUG) Log.d(TAG, "onScreenTurnedOn, seq = " + mDelayedShowingSequence);
- notifyScreenOnLocked();
- }
- }
-
- /**
- * Same semantics as {@link WindowManagerPolicy#enableKeyguard}; provide
- * a way for external stuff to override normal keyguard behavior. For instance
- * the phone app disables the keyguard when it receives incoming calls.
- */
- public void setKeyguardEnabled(boolean enabled) {
- synchronized (this) {
- if (DEBUG) Log.d(TAG, "setKeyguardEnabled(" + enabled + ")");
-
-
- mExternallyEnabled = enabled;
-
- if (!enabled && mShowing) {
- if (mExitSecureCallback != null) {
- if (DEBUG) Log.d(TAG, "in process of verifyUnlock request, ignoring");
- // we're in the process of handling a request to verify the user
- // can get past the keyguard. ignore extraneous requests to disable / reenable
- return;
- }
-
- // hiding keyguard that is showing, remember to reshow later
- if (DEBUG) Log.d(TAG, "remembering to reshow, hiding keyguard, "
- + "disabling status bar expansion");
- mNeedToReshowWhenReenabled = true;
- setStatusBarExpandable(false);
- hideLocked();
- } else if (enabled && mNeedToReshowWhenReenabled) {
- // reenabled after previously hidden, reshow
- if (DEBUG) Log.d(TAG, "previously hidden, reshowing, reenabling "
- + "status bar expansion");
- mNeedToReshowWhenReenabled = false;
- setStatusBarExpandable(true);
-
- if (mExitSecureCallback != null) {
- if (DEBUG) Log.d(TAG, "onKeyguardExitResult(false), resetting");
- mExitSecureCallback.onKeyguardExitResult(false);
- mExitSecureCallback = null;
- resetStateLocked();
- } else {
- showLocked();
-
- // block until we know the keygaurd is done drawing (and post a message
- // to unblock us after a timeout so we don't risk blocking too long
- // and causing an ANR).
- mWaitingUntilKeyguardVisible = true;
- mHandler.sendEmptyMessageDelayed(KEYGUARD_DONE_DRAWING, KEYGUARD_DONE_DRAWING_TIMEOUT_MS);
- if (DEBUG) Log.d(TAG, "waiting until mWaitingUntilKeyguardVisible is false");
- while (mWaitingUntilKeyguardVisible) {
- try {
- wait();
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- }
- if (DEBUG) Log.d(TAG, "done waiting for mWaitingUntilKeyguardVisible");
- }
- }
- }
- }
-
- /**
- * @see android.app.KeyguardManager#exitKeyguardSecurely
- */
- public void verifyUnlock(WindowManagerPolicy.OnKeyguardExitResult callback) {
- synchronized (this) {
- if (DEBUG) Log.d(TAG, "verifyUnlock");
- if (!mUpdateMonitor.isDeviceProvisioned()) {
- // don't allow this api when the device isn't provisioned
- if (DEBUG) Log.d(TAG, "ignoring because device isn't provisioned");
- callback.onKeyguardExitResult(false);
- } else if (mExternallyEnabled) {
- // this only applies when the user has externally disabled the
- // keyguard. this is unexpected and means the user is not
- // using the api properly.
- Log.w(TAG, "verifyUnlock called when not externally disabled");
- callback.onKeyguardExitResult(false);
- } else if (mExitSecureCallback != null) {
- // already in progress with someone else
- callback.onKeyguardExitResult(false);
- } else {
- mExitSecureCallback = callback;
- verifyUnlockLocked();
- }
- }
- }
-
-
- private void setStatusBarExpandable(boolean isExpandable) {
- if (mStatusBarManager == null) {
- mStatusBarManager =
- (StatusBarManager) mContext.getSystemService(Context.STATUS_BAR_SERVICE);
- }
- mStatusBarManager.disable(isExpandable ? DISABLE_NONE : DISABLE_EXPAND);
- }
-
- /**
- * Is the keyguard currently showing?
- */
- public boolean isShowing() {
- return mShowing;
- }
-
- /**
- * Given the state of the keyguard, is the input restricted?
- * Input is restricted when the keyguard is showing, or when the keyguard
- * was suppressed by an app that disabled the keyguard or we haven't been provisioned yet.
- */
- public boolean isInputRestricted() {
- return mShowing || mNeedToReshowWhenReenabled || !mUpdateMonitor.isDeviceProvisioned();
- }
-
-
- /**
- * Enable the keyguard if the settings are appropriate.
- */
- private void doKeyguard() {
- synchronized (this) {
- // if another app is disabling us, don't show
- if (!mExternallyEnabled) {
- if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled");
- return;
- }
-
- // if the keyguard is already showing, don't bother
- if (mKeyguardViewManager.isShowing()) {
- if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing");
- return;
- }
-
- // if the setup wizard hasn't run yet, don't show
- final boolean provisioned = mUpdateMonitor.isDeviceProvisioned();
- final SimCard.State state = mUpdateMonitor.getSimState();
- final boolean lockedOrMissing = state.isPinLocked() || (state == SimCard.State.ABSENT);
- if (!lockedOrMissing && !provisioned) {
- if (DEBUG) Log.d(TAG, "doKeyguard: not showing because device isn't provisioned"
- + " and the sim is not locked or missing");
- return;
- }
-
- if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen");
- showLocked();
- }
- }
-
- /**
- * Send message to keyguard telling it to reset its state.
- * @see #handleReset()
- */
- private void resetStateLocked() {
- if (DEBUG) Log.d(TAG, "resetStateLocked");
- Message msg = mHandler.obtainMessage(RESET);
- mHandler.sendMessage(msg);
- }
-
- /**
- * Send message to keyguard telling it to verify unlock
- * @see #handleVerifyUnlock()
- */
- private void verifyUnlockLocked() {
- if (DEBUG) Log.d(TAG, "verifyUnlockLocked");
- mHandler.sendEmptyMessage(VERIFY_UNLOCK);
- }
-
-
- /**
- * Send a message to keyguard telling it the screen just turned on.
- * @see #onScreenTurnedOff(int)
- * @see #handleNotifyScreenOff
- */
- private void notifyScreenOffLocked() {
- if (DEBUG) Log.d(TAG, "notifyScreenOffLocked");
- mHandler.sendEmptyMessage(NOTIFY_SCREEN_OFF);
- }
-
- /**
- * Send a message to keyguard telling it the screen just turned on.
- * @see #onScreenTurnedOn()
- * @see #handleNotifyScreenOn
- */
- private void notifyScreenOnLocked() {
- if (DEBUG) Log.d(TAG, "notifyScreenOnLocked");
- mHandler.sendEmptyMessage(NOTIFY_SCREEN_ON);
- }
-
- /**
- * Send message to keyguard telling it about a wake key so it can adjust
- * its state accordingly and then poke the wake lock when it is ready.
- * @param keyCode The wake key.
- * @see #handleWakeWhenReady
- * @see #onWakeKeyWhenKeyguardShowingTq(int)
- */
- private void wakeWhenReadyLocked(int keyCode) {
- if (DBG_WAKE) Log.d(TAG, "wakeWhenReadyLocked(" + keyCode + ")");
-
- /**
- * acquire the handoff lock that will keep the cpu running. this will
- * be released once the keyguard has set itself up and poked the other wakelock
- * in {@link #handleWakeWhenReady(int)}
- */
- mWakeAndHandOff.acquire();
-
- Message msg = mHandler.obtainMessage(WAKE_WHEN_READY, keyCode, 0);
- mHandler.sendMessage(msg);
- }
-
- /**
- * Send message to keyguard telling it to show itself
- * @see #handleShow()
- */
- private void showLocked() {
- if (DEBUG) Log.d(TAG, "showLocked");
- Message msg = mHandler.obtainMessage(SHOW);
- mHandler.sendMessage(msg);
- }
-
- /**
- * Send message to keyguard telling it to hide itself
- * @see #handleHide()
- */
- private void hideLocked() {
- if (DEBUG) Log.d(TAG, "hideLocked");
- Message msg = mHandler.obtainMessage(HIDE);
- mHandler.sendMessage(msg);
- }
-
- /**
- * {@link KeyguardUpdateMonitor} callbacks.
- */
-
- /** {@inheritDoc} */
- public void onOrientationChange(boolean inPortrait) {
-
- }
-
- /** {@inheritDoc} */
- public void onKeyboardChange(boolean isKeyboardOpen) {
- mKeyboardOpen = isKeyboardOpen;
-
- if (mKeyboardOpen && !mKeyguardViewProperties.isSecure()
- && mKeyguardViewManager.isShowing()) {
- if (DEBUG) Log.d(TAG, "bypassing keyguard on sliding open of keyboard with non-secure keyguard");
- keyguardDone(true);
- }
- }
-
- /** {@inheritDoc} */
- public void onSimStateChanged(SimCard.State simState) {
- if (DEBUG) Log.d(TAG, "onSimStateChanged: " + simState);
-
- switch (simState) {
- case ABSENT:
- // only force lock screen in case of missing sim if user hasn't
- // gone through setup wizard
- if (!mUpdateMonitor.isDeviceProvisioned()) {
- if (!isShowing()) {
- if (DEBUG) Log.d(TAG, "INTENT_VALUE_SIM_ABSENT and keygaurd isn't showing, we need "
- + "to show the keyguard since the device isn't provisioned yet.");
- doKeyguard();
- } else {
- resetStateLocked();
- }
- }
- break;
- case PIN_REQUIRED:
- case PUK_REQUIRED:
- if (!isShowing()) {
- if (DEBUG) Log.d(TAG, "INTENT_VALUE_SIM_LOCKED and keygaurd isn't showing, we need "
- + "to show the keyguard so the user can enter their sim pin");
- doKeyguard();
- } else {
- resetStateLocked();
- }
-
- break;
- case READY:
- if (isShowing()) {
- resetStateLocked();
- }
- break;
- }
- }
-
- private BroadcastReceiver mBroadCastReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (action.equals(DELAYED_KEYGUARD_ACTION)) {
-
- int sequence = intent.getIntExtra("seq", 0);
-
- if (false) Log.d(TAG, "received DELAYED_KEYGUARD_ACTION with seq = "
- + sequence + ", mDelayedShowingSequence = " + mDelayedShowingSequence);
-
- if (mDelayedShowingSequence == sequence) {
- doKeyguard();
- }
- }
- }
- };
-
-
- /**
- * When a key is received when the screen is off and the keyguard is showing,
- * we need to decide whether to actually turn on the screen, and if so, tell
- * the keyguard to prepare itself and poke the wake lock when it is ready.
- *
- * The 'Tq' suffix is per the documentation in {@link WindowManagerPolicy}.
- * Be sure not to take any action that takes a long time; any significant
- * action should be posted to a handler.
- *
- * @param keyCode The keycode of the key that woke the device
- * @return Whether we poked the wake lock (and turned the screen on)
- */
- public boolean onWakeKeyWhenKeyguardShowingTq(int keyCode) {
- if (DEBUG) Log.d(TAG, "onWakeKeyWhenKeyguardShowing(" + keyCode + ")");
-
- if (isWakeKeyWhenKeyguardShowing(keyCode)) {
- // give the keyguard view manager a chance to adjust the state of the
- // keyguard based on the key that woke the device before poking
- // the wake lock
- wakeWhenReadyLocked(keyCode);
- return true;
- } else {
- return false;
- }
- }
-
- private boolean isWakeKeyWhenKeyguardShowing(int keyCode) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_VOLUME_UP:
- case KeyEvent.KEYCODE_VOLUME_DOWN:
- case KeyEvent.KEYCODE_MUTE:
- 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:
- case KeyEvent.KEYCODE_CAMERA:
- return false;
- }
- return true;
- }
-
- /**
- * Callbacks from {@link KeyguardViewManager}.
- */
-
- /** {@inheritDoc} */
- public void pokeWakelock() {
- pokeWakelock(mKeyboardOpen ?
- AWAKE_INTERVAL_DEFAULT_KEYBOARD_OPEN_MS : AWAKE_INTERVAL_DEFAULT_MS);
- }
-
- /** {@inheritDoc} */
- public void pokeWakelock(int holdMs) {
- synchronized (this) {
- if (DBG_WAKE) Log.d(TAG, "pokeWakelock(" + holdMs + ")");
- mWakeLock.acquire();
- mHandler.removeMessages(TIMEOUT);
- mWakelockSequence++;
- Message msg = mHandler.obtainMessage(TIMEOUT, mWakelockSequence, 0);
- mHandler.sendMessageDelayed(msg, holdMs);
- }
- }
-
- /**
- * {@inheritDoc}
- *
- * @see #handleKeyguardDone
- */
- public void keyguardDone(boolean authenticated) {
- synchronized (this) {
- EventLog.writeEvent(70000, 2);
- if (DEBUG) Log.d(TAG, "keyguardDone(" + authenticated + ")");
- Message msg = mHandler.obtainMessage(KEYGUARD_DONE);
- mHandler.sendMessage(msg);
-
- if (authenticated) {
- mUpdateMonitor.clearFailedAttempts();
- }
-
- if (mExitSecureCallback != null) {
- mExitSecureCallback.onKeyguardExitResult(authenticated);
- mExitSecureCallback = null;
-
- if (authenticated) {
- // after succesfully exiting securely, no need to reshow
- // the keyguard when they've released the lock
- mExternallyEnabled = true;
- mNeedToReshowWhenReenabled = false;
- setStatusBarExpandable(true);
- }
- }
- }
- }
-
- /**
- * {@inheritDoc}
- *
- * @see #handleKeyguardDoneDrawing
- */
- public void keyguardDoneDrawing() {
- mHandler.sendEmptyMessage(KEYGUARD_DONE_DRAWING);
- }
-
- /**
- * This handler will be associated with the policy thread, which will also
- * be the UI thread of the keyguard. Since the apis of the policy, and therefore
- * this class, can be called by other threads, any action that directly
- * interacts with the keyguard ui should be posted to this handler, rather
- * than called directly.
- */
- private Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg)
- {
- switch (msg.what)
- {
- case TIMEOUT:
- handleTimeout(msg.arg1);
- return ;
- case SHOW:
- handleShow();
- return ;
- case HIDE:
- handleHide();
- return ;
- case RESET:
- handleReset();
- return ;
- case VERIFY_UNLOCK:
- handleVerifyUnlock();
- return;
- case NOTIFY_SCREEN_OFF:
- handleNotifyScreenOff();
- return;
- case NOTIFY_SCREEN_ON:
- handleNotifyScreenOn();
- return;
- case WAKE_WHEN_READY:
- handleWakeWhenReady(msg.arg1);
- return;
- case KEYGUARD_DONE:
- handleKeyguardDone();
- return;
- case KEYGUARD_DONE_DRAWING:
- handleKeyguardDoneDrawing();
- }
- }
- };
-
- /**
- * @see #keyguardDone
- * @see #KEYGUARD_DONE
- */
- private void handleKeyguardDone() {
- if (DEBUG) Log.d(TAG, "handleKeyguardDone");
- handleHide();
- mPM.userActivity(SystemClock.uptimeMillis(), true);
- mWakeLock.release();
- }
-
- /**
- * @see #keyguardDoneDrawing
- * @see #KEYGUARD_DONE_DRAWING
- */
- private void handleKeyguardDoneDrawing() {
- synchronized(this) {
- if (false) Log.d(TAG, "handleKeyguardDoneDrawing");
- if (mWaitingUntilKeyguardVisible) {
- if (DEBUG) Log.d(TAG, "handleKeyguardDoneDrawing: notifying mWaitingUntilKeyguardVisible");
- mWaitingUntilKeyguardVisible = false;
- notifyAll();
-
- // there will usually be two of these sent, one as a timeout, and one
- // as a result of the callback, so remove any remaining messages from
- // the queue
- mHandler.removeMessages(KEYGUARD_DONE_DRAWING);
- }
- }
- }
-
- /**
- * Handles the message sent by {@link #pokeWakelock}
- * @param seq used to determine if anything has changed since the message
- * was sent.
- * @see #TIMEOUT
- */
- private void handleTimeout(int seq) {
- synchronized (KeyguardViewMediator.this) {
- if (DEBUG) Log.d(TAG, "handleTimeout");
- if (seq == mWakelockSequence) {
- mWakeLock.release();
- }
- }
- }
-
- /**
- * Handle message sent by {@link #showLocked}.
- * @see #SHOW
- */
- private void handleShow() {
- synchronized (KeyguardViewMediator.this) {
- if (DEBUG) Log.d(TAG, "handleShow");
- if (!mSystemReady) return;
-
- // while we're showing, we control the wake state, so ask the power
- // manager not to honor request for userActivity.
- mRealPowerManager.enableUserActivity(false);
-
- mCallback.onKeyguardShow();
- mKeyguardViewManager.show();
- mShowing = true;
- }
- }
-
- /**
- * Handle message sent by {@link #hideLocked()}
- * @see #HIDE
- */
- private void handleHide() {
- synchronized (KeyguardViewMediator.this) {
- if (DEBUG) Log.d(TAG, "handleHide");
- // When we go away, tell the poewr manager to honor requests from userActivity.
- mRealPowerManager.enableUserActivity(true);
-
- mKeyguardViewManager.hide();
- mShowing = false;
- }
- }
-
- /**
- * Handle message sent by {@link #wakeWhenReadyLocked(int)}
- * @param keyCode The key that woke the device.
- * @see #WAKE_WHEN_READY
- */
- private void handleWakeWhenReady(int keyCode) {
- synchronized (KeyguardViewMediator.this) {
- if (DBG_WAKE) Log.d(TAG, "handleWakeWhenReady(" + keyCode + ")");
-
- // this should result in a call to 'poke wakelock' which will set a timeout
- // on releasing the wakelock
- mKeyguardViewManager.wakeWhenReadyTq(keyCode);
-
- /**
- * Now that the keyguard is ready and has poked the wake lock, we can
- * release the handoff wakelock
- */
- mWakeAndHandOff.release();
-
- if (!mWakeLock.isHeld()) {
- Log.w(TAG, "mKeyguardViewManager.wakeWhenReadyTq did not poke wake lock");
- }
- }
- }
-
- /**
- * Handle message sent by {@link #resetStateLocked()}
- * @see #RESET
- */
- private void handleReset() {
- synchronized (KeyguardViewMediator.this) {
- if (DEBUG) Log.d(TAG, "handleReset");
- mKeyguardViewManager.reset();
- }
- }
-
- /**
- * Handle message sent by {@link #verifyUnlock}
- * @see #RESET
- */
- private void handleVerifyUnlock() {
- synchronized (KeyguardViewMediator.this) {
- if (DEBUG) Log.d(TAG, "handleVerifyUnlock");
- mKeyguardViewManager.verifyUnlock();
- mShowing = true;
- }
- }
-
- /**
- * Handle message sent by {@link #notifyScreenOffLocked()}
- * @see #NOTIFY_SCREEN_OFF
- */
- private void handleNotifyScreenOff() {
- synchronized (KeyguardViewMediator.this) {
- if (DEBUG) Log.d(TAG, "handleNotifyScreenOff");
- mKeyguardViewManager.onScreenTurnedOff();
- }
- }
-
- /**
- * Handle message sent by {@link #notifyScreenOnLocked()}
- * @see #NOTIFY_SCREEN_ON
- */
- private void handleNotifyScreenOn() {
- synchronized (KeyguardViewMediator.this) {
- if (DEBUG) Log.d(TAG, "handleNotifyScreenOn");
- mKeyguardViewManager.onScreenTurnedOn();
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import android.content.Context;
-
-/**
- * Defines operations necessary for showing a keyguard, including how to create
- * it, and various properties that are useful to be able to query independant
- * of whether the keyguard instance is around or not.
- */
-public interface KeyguardViewProperties {
-
- /**
- * Create a keyguard view.
- * @param context the context to use when creating the view.
- * @param updateMonitor configuration may be based on this.
- * @param controller for talking back with the containing window.
- * @return the view.
- */
- KeyguardViewBase createKeyguardView(Context context,
- KeyguardUpdateMonitor updateMonitor,
- KeyguardWindowController controller);
-
- /**
- * Would the keyguard be secure right now?
- * @return Whether the keyguard is currently secure, meaning it will block
- * the user from getting past it until the user enters some sort of PIN.
- */
- boolean isSecure();
-
-}
+++ /dev/null
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-/**
- * Interface passed to the keyguard view, for it to call up to control
- * its containing window.
- */
-public interface KeyguardWindowController {
- /**
- * Control whether the window needs input -- that is if it has
- * text fields and thus should allow input method interaction.
- */
- void setNeedsInput(boolean needsInput);
-}
+++ /dev/null
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import android.accounts.AccountsServiceConstants;
-import android.accounts.IAccountsService;
-import android.app.AlertDialog;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.SystemProperties;
-import com.android.internal.telephony.SimCard;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.WindowManager;
-import com.android.internal.R;
-import com.android.internal.widget.LockPatternUtils;
-
-/**
- * The host view for all of the screens of the pattern unlock screen. There are
- * two {@link Mode}s of operation, lock and unlock. This will show the appropriate
- * screen, and listen for callbacks via {@link com.android.internal.policy.impl.KeyguardScreenCallback
- * from the current screen.
- *
- * This view, in turn, communicates back to {@link com.android.internal.policy.impl.KeyguardViewManager}
- * via its {@link com.android.internal.policy.impl.KeyguardViewCallback}, as appropriate.
- */
-public class LockPatternKeyguardView extends KeyguardViewBase {
-
- // intent action for launching emergency dialer activity.
- static final String ACTION_EMERGENCY_DIAL = "com.android.phone.EmergencyDialer.DIAL";
-
- private static final boolean DEBUG = false;
- private static final String TAG = "LockPatternKeyguardView";
-
- private final KeyguardUpdateMonitor mUpdateMonitor;
- private final KeyguardWindowController mWindowController;
-
- private View mLockScreen;
- private View mUnlockScreen;
-
- private boolean mScreenOn = false;
- private boolean mHasAccount = false; // assume they don't have an account until we know better
-
-
- /**
- * The current {@link KeyguardScreen} will use this to communicate back to us.
- */
- KeyguardScreenCallback mKeyguardScreenCallback;
-
-
- private boolean mRequiresSim;
-
-
- /**
- * Either a lock screen (an informational keyguard screen), or an unlock
- * screen (a means for unlocking the device) is shown at any given time.
- */
- enum Mode {
- LockScreen,
- UnlockScreen
- }
-
- /**
- * The different types screens available for {@link Mode#UnlockScreen}.
- * @see com.android.internal.policy.impl.LockPatternKeyguardView#getUnlockMode()
- */
- enum UnlockMode {
-
- /**
- * Unlock by drawing a pattern.
- */
- Pattern,
-
- /**
- * Unlock by entering a sim pin.
- */
- SimPin,
-
- /**
- * Unlock by entering an account's login and password.
- */
- Account
- }
-
- /**
- * The current mode.
- */
- private Mode mMode = Mode.LockScreen;
-
- /**
- * Keeps track of what mode the current unlock screen is
- */
- private UnlockMode mUnlockScreenMode;
-
- /**
- * If true, it means we are in the process of verifying that the user
- * can get past the lock screen per {@link #verifyUnlock()}
- */
- private boolean mIsVerifyUnlockOnly = false;
-
-
- /**
- * Used to lookup the state of the lock pattern
- */
- private final LockPatternUtils mLockPatternUtils;
-
- /**
- * Used to fetch accounts from GLS.
- */
- private ServiceConnection mServiceConnection;
-
- /**
- * @return Whether we are stuck on the lock screen because the sim is
- * missing.
- */
- private boolean stuckOnLockScreenBecauseSimMissing() {
- return mRequiresSim
- && (!mUpdateMonitor.isDeviceProvisioned())
- && (mUpdateMonitor.getSimState() == SimCard.State.ABSENT);
- }
-
- /**
- * @param context Used to inflate, and create views.
- * @param updateMonitor Knows the state of the world, and passed along to each
- * screen so they can use the knowledge, and also register for callbacks
- * on dynamic information.
- * @param lockPatternUtils Used to look up state of lock pattern.
- */
- public LockPatternKeyguardView(
- Context context,
- KeyguardUpdateMonitor updateMonitor,
- LockPatternUtils lockPatternUtils,
- KeyguardWindowController controller) {
- super(context);
-
- asyncCheckForAccount();
-
- mRequiresSim =
- TextUtils.isEmpty(SystemProperties.get("keyguard.no_require_sim"));
-
- mUpdateMonitor = updateMonitor;
- mLockPatternUtils = lockPatternUtils;
- mWindowController = controller;
-
- mMode = getInitialMode();
-
- mKeyguardScreenCallback = new KeyguardScreenCallback() {
-
- public void goToLockScreen() {
- if (mIsVerifyUnlockOnly) {
- // navigating away from unlock screen during verify mode means
- // we are done and the user failed to authenticate.
- mIsVerifyUnlockOnly = false;
- getCallback().keyguardDone(false);
- } else {
- updateScreen(Mode.LockScreen);
- }
- }
-
- public void goToUnlockScreen() {
- final SimCard.State simState = mUpdateMonitor.getSimState();
- if (stuckOnLockScreenBecauseSimMissing()
- || (simState == SimCard.State.PUK_REQUIRED)){
- // stuck on lock screen when sim missing or puk'd
- return;
- }
- if (!isSecure()) {
- getCallback().keyguardDone(true);
- } else {
- updateScreen(Mode.UnlockScreen);
- }
- }
-
- public boolean isSecure() {
- return LockPatternKeyguardView.this.isSecure();
- }
-
- public boolean isVerifyUnlockOnly() {
- return mIsVerifyUnlockOnly;
- }
-
- public void recreateMe() {
- recreateScreens();
- }
-
- public void takeEmergencyCallAction() {
- Intent intent = new Intent(ACTION_EMERGENCY_DIAL);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
- getContext().startActivity(intent);
- }
-
- public void pokeWakelock() {
- getCallback().pokeWakelock();
- }
-
- public void pokeWakelock(int millis) {
- getCallback().pokeWakelock(millis);
- }
-
- public void keyguardDone(boolean authenticated) {
- getCallback().keyguardDone(authenticated);
- }
-
- public void keyguardDoneDrawing() {
- // irrelevant to keyguard screen, they shouldn't be calling this
- }
-
- public void reportFailedPatternAttempt() {
- mUpdateMonitor.reportFailedAttempt();
- final int failedAttempts = mUpdateMonitor.getFailedAttempts();
- if (mHasAccount && failedAttempts ==
- (LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET
- - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) {
- showAlmostAtAccountLoginDialog();
- } else if (mHasAccount && failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) {
- mLockPatternUtils.setPermanentlyLocked(true);
- updateScreen(mMode);
- } else if ((failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)
- == 0) {
- showTimeoutDialog();
- }
- }
-
- public boolean doesFallbackUnlockScreenExist() {
- return mHasAccount;
- }
- };
-
- /**
- * We'll get key events the current screen doesn't use. see
- * {@link KeyguardViewBase#onKeyDown(int, android.view.KeyEvent)}
- */
- setFocusableInTouchMode(true);
- setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
-
- // create both the lock and unlock screen so they are quickly available
- // when the screen turns on
- mLockScreen = createLockScreen();
- addView(mLockScreen);
- final UnlockMode unlockMode = getUnlockMode();
- mUnlockScreen = createUnlockScreenFor(unlockMode);
- mUnlockScreenMode = unlockMode;
- addView(mUnlockScreen);
- updateScreen(mMode);
- }
-
- /**
- * Asynchronously checks for at least one account. This will set mHasAccount
- * to true if an account is found.
- */
- private void asyncCheckForAccount() {
-
- mServiceConnection = new ServiceConnection() {
- public void onServiceConnected(ComponentName className, IBinder service) {
- try {
- IAccountsService accountsService = IAccountsService.Stub.asInterface(service);
- String accounts[] = accountsService.getAccounts();
- mHasAccount = (accounts.length > 0);
- } catch (RemoteException e) {
- // Not much we can do here...
- Log.e(TAG, "Gls died while attempting to get accounts: " + e);
- } finally {
- getContext().unbindService(mServiceConnection);
- mServiceConnection = null;
- }
- }
-
- public void onServiceDisconnected(ComponentName className) {
- // nothing to do here
- }
- };
- boolean status = getContext().bindService(AccountsServiceConstants.SERVICE_INTENT,
- mServiceConnection, Context.BIND_AUTO_CREATE);
- if (!status) Log.e(TAG, "Failed to bind to GLS while checking for account");
- }
-
- @Override
- public void reset() {
- mIsVerifyUnlockOnly = false;
- updateScreen(getInitialMode());
- }
-
- @Override
- public void onScreenTurnedOff() {
- mScreenOn = false;
- if (mMode == Mode.LockScreen) {
- ((KeyguardScreen) mLockScreen).onPause();
- } else {
- ((KeyguardScreen) mUnlockScreen).onPause();
- }
- }
-
- @Override
- public void onScreenTurnedOn() {
- mScreenOn = true;
- if (mMode == Mode.LockScreen) {
- ((KeyguardScreen) mLockScreen).onResume();
- } else {
- ((KeyguardScreen) mUnlockScreen).onResume();
- }
- }
-
-
- private void recreateScreens() {
- if (mLockScreen.getVisibility() == View.VISIBLE) {
- ((KeyguardScreen) mLockScreen).onPause();
- }
- ((KeyguardScreen) mLockScreen).cleanUp();
- removeViewInLayout(mLockScreen);
-
- mLockScreen = createLockScreen();
- mLockScreen.setVisibility(View.INVISIBLE);
- addView(mLockScreen);
-
- if (mUnlockScreen.getVisibility() == View.VISIBLE) {
- ((KeyguardScreen) mUnlockScreen).onPause();
- }
- ((KeyguardScreen) mUnlockScreen).cleanUp();
- removeViewInLayout(mUnlockScreen);
-
- final UnlockMode unlockMode = getUnlockMode();
- mUnlockScreen = createUnlockScreenFor(unlockMode);
- mUnlockScreen.setVisibility(View.INVISIBLE);
- mUnlockScreenMode = unlockMode;
- addView(mUnlockScreen);
-
- updateScreen(mMode);
- }
-
-
- @Override
- public void wakeWhenReadyTq(int keyCode) {
- if (DEBUG) Log.d(TAG, "onWakeKey");
- if (keyCode == KeyEvent.KEYCODE_MENU && isSecure() && (mMode == Mode.LockScreen)
- && (mUpdateMonitor.getSimState() != SimCard.State.PUK_REQUIRED)) {
- if (DEBUG) Log.d(TAG, "switching screens to unlock screen because wake key was MENU");
- updateScreen(Mode.UnlockScreen);
- getCallback().pokeWakelock();
- } else {
- if (DEBUG) Log.d(TAG, "poking wake lock immediately");
- getCallback().pokeWakelock();
- }
- }
-
- @Override
- public void verifyUnlock() {
- if (!isSecure()) {
- // non-secure keyguard screens are successfull by default
- getCallback().keyguardDone(true);
- } else if (mUnlockScreenMode != UnlockMode.Pattern) {
- // can only verify unlock when in pattern mode
- getCallback().keyguardDone(false);
- } else {
- // otherwise, go to the unlock screen, see if they can verify it
- mIsVerifyUnlockOnly = true;
- updateScreen(Mode.UnlockScreen);
- }
- }
-
- @Override
- public void cleanUp() {
- ((KeyguardScreen) mLockScreen).onPause();
- ((KeyguardScreen) mLockScreen).cleanUp();
- ((KeyguardScreen) mUnlockScreen).onPause();
- ((KeyguardScreen) mUnlockScreen).cleanUp();
- }
-
- private boolean isSecure() {
- UnlockMode unlockMode = getUnlockMode();
- if (unlockMode == UnlockMode.Pattern) {
- return mLockPatternUtils.isLockPatternEnabled();
- } else if (unlockMode == UnlockMode.SimPin) {
- return mUpdateMonitor.getSimState() == SimCard.State.PIN_REQUIRED
- || mUpdateMonitor.getSimState() == SimCard.State.PUK_REQUIRED;
- } else if (unlockMode == UnlockMode.Account) {
- return true;
- } else {
- throw new IllegalStateException("unknown unlock mode " + unlockMode);
- }
- }
-
- private void updateScreen(final Mode mode) {
-
- mMode = mode;
-
- final View goneScreen = (mode == Mode.LockScreen) ? mUnlockScreen : mLockScreen;
- final View visibleScreen = (mode == Mode.LockScreen)
- ? mLockScreen : getUnlockScreenForCurrentUnlockMode();
-
-
- if (mScreenOn) {
- if (goneScreen.getVisibility() == View.VISIBLE) {
- ((KeyguardScreen) goneScreen).onPause();
- }
- if (visibleScreen.getVisibility() != View.VISIBLE) {
- ((KeyguardScreen) visibleScreen).onResume();
- }
- }
-
- goneScreen.setVisibility(View.GONE);
- visibleScreen.setVisibility(View.VISIBLE);
-
- mWindowController.setNeedsInput(((KeyguardScreen)visibleScreen).needsInput());
-
- if (!visibleScreen.requestFocus()) {
- throw new IllegalStateException("keyguard screen must be able to take "
- + "focus when shown " + visibleScreen.getClass().getCanonicalName());
- }
- }
-
- View createLockScreen() {
- return new LockScreen(
- mContext,
- mLockPatternUtils,
- mUpdateMonitor,
- mKeyguardScreenCallback);
- }
-
- View createUnlockScreenFor(UnlockMode unlockMode) {
- if (unlockMode == UnlockMode.Pattern) {
- return new UnlockScreen(
- mContext,
- mLockPatternUtils,
- mUpdateMonitor,
- mKeyguardScreenCallback,
- mUpdateMonitor.getFailedAttempts());
- } else if (unlockMode == UnlockMode.SimPin) {
- return new SimUnlockScreen(
- mContext,
- mUpdateMonitor,
- mKeyguardScreenCallback);
- } else if (unlockMode == UnlockMode.Account) {
- try {
- return new AccountUnlockScreen(
- mContext,
- mKeyguardScreenCallback,
- mLockPatternUtils);
- } catch (IllegalStateException e) {
- Log.i(TAG, "Couldn't instantiate AccountUnlockScreen"
- + " (IAccountsService isn't available)");
- // TODO: Need a more general way to provide a
- // platform-specific fallback UI here.
- // For now, if we can't display the account login
- // unlock UI, just bring back the regular "Pattern" unlock mode.
-
- // (We do this by simply returning a regular UnlockScreen
- // here. This means that the user will still see the
- // regular pattern unlock UI, regardless of the value of
- // mUnlockScreenMode or whether or not we're in the
- // "permanently locked" state.)
- return createUnlockScreenFor(UnlockMode.Pattern);
- }
- } else {
- throw new IllegalArgumentException("unknown unlock mode " + unlockMode);
- }
- }
-
- private View getUnlockScreenForCurrentUnlockMode() {
- final UnlockMode unlockMode = getUnlockMode();
-
- // if a screen exists for the correct mode, we're done
- if (unlockMode == mUnlockScreenMode) {
- return mUnlockScreen;
- }
-
- // remember the mode
- mUnlockScreenMode = unlockMode;
-
- // unlock mode has changed and we have an existing old unlock screen
- // to clean up
- if (mScreenOn && (mUnlockScreen.getVisibility() == View.VISIBLE)) {
- ((KeyguardScreen) mUnlockScreen).onPause();
- }
- ((KeyguardScreen) mUnlockScreen).cleanUp();
- removeViewInLayout(mUnlockScreen);
-
- // create the new one
- mUnlockScreen = createUnlockScreenFor(unlockMode);
- mUnlockScreen.setVisibility(View.INVISIBLE);
- addView(mUnlockScreen);
- return mUnlockScreen;
- }
-
- /**
- * Given the current state of things, what should be the initial mode of
- * the lock screen (lock or unlock).
- */
- private Mode getInitialMode() {
- final SimCard.State simState = mUpdateMonitor.getSimState();
- if (stuckOnLockScreenBecauseSimMissing() || (simState == SimCard.State.PUK_REQUIRED)) {
- return Mode.LockScreen;
- } else if (mUpdateMonitor.isKeyboardOpen() && isSecure()) {
- return Mode.UnlockScreen;
- } else {
- return Mode.LockScreen;
- }
- }
-
- /**
- * Given the current state of things, what should the unlock screen be?
- */
- private UnlockMode getUnlockMode() {
- final SimCard.State simState = mUpdateMonitor.getSimState();
- if (simState == SimCard.State.PIN_REQUIRED || simState == SimCard.State.PUK_REQUIRED) {
- return UnlockMode.SimPin;
- } else {
- return mLockPatternUtils.isPermanentlyLocked() ?
- UnlockMode.Account:
- UnlockMode.Pattern;
- }
- }
-
- private void showTimeoutDialog() {
- int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;
- String message = mContext.getString(
- R.string.lockscreen_too_many_failed_attempts_dialog_message,
- mUpdateMonitor.getFailedAttempts(),
- timeoutInSeconds);
- final AlertDialog dialog = new AlertDialog.Builder(mContext)
- .setTitle(null)
- .setMessage(message)
- .setNeutralButton(R.string.ok, null)
- .create();
- dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
- dialog.getWindow().setFlags(
- WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
- WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
- dialog.show();
- }
-
- private void showAlmostAtAccountLoginDialog() {
- int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;
- String message = mContext.getString(
- R.string.lockscreen_failed_attempts_almost_glogin,
- LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT,
- LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT,
- timeoutInSeconds);
- final AlertDialog dialog = new AlertDialog.Builder(mContext)
- .setTitle(null)
- .setMessage(message)
- .setNeutralButton(R.string.ok, null)
- .create();
- dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
- dialog.getWindow().setFlags(
- WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
- WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
- dialog.show();
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import com.android.internal.widget.LockPatternUtils;
-
-import android.content.Context;
-import com.android.internal.telephony.SimCard;
-
-/**
- * Knows how to create a lock pattern keyguard view, and answer questions about
- * it (even if it hasn't been created, per the interface specs).
- */
-public class LockPatternKeyguardViewProperties implements KeyguardViewProperties {
-
- private final LockPatternUtils mLockPatternUtils;
- private final KeyguardUpdateMonitor mUpdateMonitor;
-
- /**
- * @param lockPatternUtils Used to know whether the pattern enabled, and passed
- * onto the keygaurd view when it is created.
- * @param updateMonitor Used to know whether the sim pin is enabled, and passed
- * onto the keyguard view when it is created.
- */
- public LockPatternKeyguardViewProperties(LockPatternUtils lockPatternUtils,
- KeyguardUpdateMonitor updateMonitor) {
- mLockPatternUtils = lockPatternUtils;
- mUpdateMonitor = updateMonitor;
- }
-
- public KeyguardViewBase createKeyguardView(Context context,
- KeyguardUpdateMonitor updateMonitor,
- KeyguardWindowController controller) {
- return new LockPatternKeyguardView(context, updateMonitor,
- mLockPatternUtils, controller);
- }
-
- public boolean isSecure() {
- return isLockPatternSecure() || isSimPinSecure();
- }
-
- private boolean isLockPatternSecure() {
- return mLockPatternUtils.isLockPatternEnabled() && mLockPatternUtils
- .savedPatternExists();
- }
-
- private boolean isSimPinSecure() {
- final SimCard.State simState = mUpdateMonitor.getSimState();
- return (simState == SimCard.State.PIN_REQUIRED || simState == SimCard.State.PUK_REQUIRED
- || simState == SimCard.State.ABSENT);
- }
-
-}
+++ /dev/null
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import com.android.internal.R;
-import com.android.internal.widget.LockPatternUtils;
-
-import android.content.Context;
-import android.text.format.DateFormat;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-import com.android.internal.telephony.SimCard;
-
-import java.util.Date;
-
-/**
- * The screen within {@link LockPatternKeyguardView} that shows general
- * information about the device depending on its state, and how to get
- * past it, as applicable.
- */
-class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateMonitor.InfoCallback,
- KeyguardUpdateMonitor.SimStateCallback, KeyguardUpdateMonitor.ConfigurationChangeCallback {
- private final LockPatternUtils mLockPatternUtils;
- private final KeyguardUpdateMonitor mUpdateMonitor;
- private final KeyguardScreenCallback mCallback;
-
- private TextView mHeaderSimOk1;
- private TextView mHeaderSimOk2;
-
- private TextView mHeaderSimBad1;
- private TextView mHeaderSimBad2;
-
- private TextView mTime;
- private TextView mDate;
-
- private ViewGroup mBatteryInfoGroup;
- private ImageView mBatteryInfoIcon;
- private TextView mBatteryInfoText;
- private View mBatteryInfoSpacer;
-
- private ViewGroup mNextAlarmGroup;
- private TextView mAlarmText;
- private View mAlarmSpacer;
-
- private ViewGroup mScreenLockedMessageGroup;
-
- private TextView mLockInstructions;
-
- private Button mEmergencyCallButton;
-
- /**
- * false means sim is missing or PUK'd
- */
- private boolean mSimOk = true;
-
- // are we showing battery information?
- private boolean mShowingBatteryInfo = false;
-
- // last known plugged in state
- private boolean mPluggedIn = false;
-
- // last known battery level
- private int mBatteryLevel = 100;
-
-
- private View[] mOnlyVisibleWhenSimOk;
-
- private View[] mOnlyVisibleWhenSimNotOk;
-
- /**
- * @param context Used to setup the view.
- * @param lockPatternUtils Used to know the state of the lock pattern settings.
- * @param updateMonitor Used to register for updates on various keyguard related
- * state, and query the initial state at setup.
- * @param callback Used to communicate back to the host keyguard view.
- */
- LockScreen(Context context, LockPatternUtils lockPatternUtils,
- KeyguardUpdateMonitor updateMonitor,
- KeyguardScreenCallback callback) {
- super(context);
- mLockPatternUtils = lockPatternUtils;
- mUpdateMonitor = updateMonitor;
- mCallback = callback;
-
- final LayoutInflater inflater = LayoutInflater.from(context);
- inflater.inflate(R.layout.keyguard_screen_lock, this, true);
-
- mSimOk = isSimOk(updateMonitor.getSimState());
- mShowingBatteryInfo = updateMonitor.shouldShowBatteryInfo();
- mPluggedIn = updateMonitor.isDevicePluggedIn();
- mBatteryLevel = updateMonitor.getBatteryLevel();
-
- mHeaderSimOk1 = (TextView) findViewById(R.id.headerSimOk1);
- mHeaderSimOk2 = (TextView) findViewById(R.id.headerSimOk2);
-
- mHeaderSimBad1 = (TextView) findViewById(R.id.headerSimBad1);
- mHeaderSimBad2 = (TextView) findViewById(R.id.headerSimBad2);
-
- mTime = (TextView) findViewById(R.id.time);
- mDate = (TextView) findViewById(R.id.date);
-
- mBatteryInfoGroup = (ViewGroup) findViewById(R.id.batteryInfo);
- mBatteryInfoIcon = (ImageView) findViewById(R.id.batteryInfoIcon);
- mBatteryInfoText = (TextView) findViewById(R.id.batteryInfoText);
- mBatteryInfoSpacer = findViewById(R.id.batteryInfoSpacer);
-
- mNextAlarmGroup = (ViewGroup) findViewById(R.id.nextAlarmInfo);
- mAlarmText = (TextView) findViewById(R.id.nextAlarmText);
- mAlarmSpacer = findViewById(R.id.nextAlarmSpacer);
-
- mScreenLockedMessageGroup = (ViewGroup) findViewById(R.id.screenLockedInfo);
-
- mLockInstructions = (TextView) findViewById(R.id.lockInstructions);
-
- mEmergencyCallButton = (Button) findViewById(R.id.emergencyCallButton);
-
- mEmergencyCallButton.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- mCallback.takeEmergencyCallAction();
- }
- });
-
- mOnlyVisibleWhenSimOk = new View[] {
- mHeaderSimOk1,
- mHeaderSimOk2,
- mBatteryInfoGroup,
- mBatteryInfoSpacer,
- mNextAlarmGroup,
- mAlarmSpacer,
- mScreenLockedMessageGroup,
- mLockInstructions
- };
-
- mOnlyVisibleWhenSimNotOk = new View[] {
- mHeaderSimBad1,
- mHeaderSimBad2,
- mEmergencyCallButton
- };
-
- setFocusable(true);
- setFocusableInTouchMode(true);
- setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
-
- refreshBatteryDisplay();
- refreshAlarmDisplay();
- refreshTimeAndDateDisplay();
- refreshUnlockIntructions();
- refreshViewsWRTSimOk();
- refreshSimOkHeaders(mUpdateMonitor.getTelephonyPlmn(), mUpdateMonitor.getTelephonySpn());
-
- updateMonitor.registerInfoCallback(this);
- updateMonitor.registerSimStateCallback(this);
- updateMonitor.registerConfigurationChangeCallback(this);
- }
-
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_MENU) {
- mCallback.goToUnlockScreen();
- }
- return false;
- }
-
- private void refreshViewsWRTSimOk() {
- if (mSimOk) {
- for (int i = 0; i < mOnlyVisibleWhenSimOk.length; i++) {
- final View view = mOnlyVisibleWhenSimOk[i];
- if (view == null) throw new RuntimeException("index " + i + " null");
- view.setVisibility(View.VISIBLE);
- }
- for (int i = 0; i < mOnlyVisibleWhenSimNotOk.length; i++) {
- final View view = mOnlyVisibleWhenSimNotOk[i];
- view.setVisibility(View.GONE);
- }
- refreshSimOkHeaders(mUpdateMonitor.getTelephonyPlmn(), mUpdateMonitor.getTelephonySpn());
- refreshAlarmDisplay();
- refreshBatteryDisplay();
- } else {
- for (int i = 0; i < mOnlyVisibleWhenSimOk.length; i++) {
- final View view = mOnlyVisibleWhenSimOk[i];
- view.setVisibility(View.GONE);
- }
- for (int i = 0; i < mOnlyVisibleWhenSimNotOk.length; i++) {
- final View view = mOnlyVisibleWhenSimNotOk[i];
- view.setVisibility(View.VISIBLE);
- }
- refreshSimBadInfo();
- }
- }
-
- private void refreshSimBadInfo() {
- final SimCard.State simState = mUpdateMonitor.getSimState();
- if (simState == SimCard.State.PUK_REQUIRED) {
- mHeaderSimBad1.setText(R.string.lockscreen_sim_puk_locked_message);
- mHeaderSimBad2.setText(R.string.lockscreen_sim_puk_locked_instructions);
- } else if (simState == SimCard.State.ABSENT) {
- mHeaderSimBad1.setText(R.string.lockscreen_missing_sim_message);
- mHeaderSimBad2.setVisibility(View.GONE);
- //mHeaderSimBad2.setText(R.string.lockscreen_missing_sim_instructions);
- } else {
- mHeaderSimBad1.setVisibility(View.GONE);
- mHeaderSimBad2.setVisibility(View.GONE);
- }
- }
-
- private void refreshUnlockIntructions() {
- if (mLockPatternUtils.isLockPatternEnabled()
- || mUpdateMonitor.getSimState() == SimCard.State.PIN_REQUIRED) {
- mLockInstructions.setText(R.string.lockscreen_instructions_when_pattern_enabled);
- } else {
- mLockInstructions.setText(R.string.lockscreen_instructions_when_pattern_disabled);
- }
- }
-
- private void refreshAlarmDisplay() {
- String nextAlarmText = mLockPatternUtils.getNextAlarm();
- if (nextAlarmText != null && mSimOk) {
- setAlarmInfoVisible(true);
- mAlarmText.setText(nextAlarmText);
- } else {
- setAlarmInfoVisible(false);
- }
- }
-
- private void setAlarmInfoVisible(boolean visible) {
- final int visibilityFlag = visible ? View.VISIBLE : View.GONE;
- mNextAlarmGroup.setVisibility(visibilityFlag);
- mAlarmSpacer.setVisibility(visibilityFlag);
- }
-
-
- public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn,
- int batteryLevel) {
- mShowingBatteryInfo = showBatteryInfo;
- mPluggedIn = pluggedIn;
- mBatteryLevel = batteryLevel;
-
- refreshBatteryDisplay();
- }
-
- private void refreshBatteryDisplay() {
- if (!mShowingBatteryInfo || !mSimOk) {
- mBatteryInfoGroup.setVisibility(View.GONE);
- mBatteryInfoSpacer.setVisibility(View.GONE);
- return;
- }
- mBatteryInfoGroup.setVisibility(View.VISIBLE);
- mBatteryInfoSpacer.setVisibility(View.VISIBLE);
-
- if (mPluggedIn) {
- mBatteryInfoIcon.setImageResource(R.drawable.ic_lock_idle_charging);
- mBatteryInfoText.setText(
- getContext().getString(R.string.lockscreen_plugged_in, mBatteryLevel));
- } else {
- mBatteryInfoIcon.setImageResource(R.drawable.ic_lock_idle_low_battery);
- mBatteryInfoText.setText(R.string.lockscreen_low_battery);
- }
- }
-
- public void onTimeChanged() {
- refreshTimeAndDateDisplay();
- }
-
- private void refreshTimeAndDateDisplay() {
- Date now = new Date();
- mTime.setText(DateFormat.getTimeFormat(getContext()).format(now));
- mDate.setText(DateFormat.getDateFormat(getContext()).format(now));
- }
-
- public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) {
- refreshSimOkHeaders(plmn, spn);
- }
-
- private void refreshSimOkHeaders(CharSequence plmn, CharSequence spn) {
- final SimCard.State simState = mUpdateMonitor.getSimState();
- if (simState == SimCard.State.READY) {
- if (plmn != null) {
- mHeaderSimOk1.setVisibility(View.VISIBLE);
- mHeaderSimOk1.setText(plmn);
- } else {
- mHeaderSimOk1.setVisibility(View.GONE);
- }
-
- if (spn != null) {
- mHeaderSimOk2.setVisibility(View.VISIBLE);
- mHeaderSimOk2.setText(spn);
- } else {
- mHeaderSimOk2.setVisibility(View.GONE);
- }
- } else if (simState == SimCard.State.PIN_REQUIRED) {
- mHeaderSimOk1.setVisibility(View.VISIBLE);
- mHeaderSimOk1.setText(R.string.lockscreen_sim_locked_message);
- mHeaderSimOk2.setVisibility(View.GONE);
- } else if (simState == SimCard.State.ABSENT) {
- mHeaderSimOk1.setVisibility(View.VISIBLE);
- mHeaderSimOk1.setText(R.string.lockscreen_missing_sim_message_short);
- mHeaderSimOk2.setVisibility(View.GONE);
- } else if (simState == SimCard.State.NETWORK_LOCKED) {
- mHeaderSimOk1.setVisibility(View.VISIBLE);
- mHeaderSimOk1.setText(R.string.lockscreen_network_locked_message);
- mHeaderSimOk2.setVisibility(View.GONE);
- }
- }
-
- public void onSimStateChanged(SimCard.State simState) {
- mSimOk = isSimOk(simState);
- refreshViewsWRTSimOk();
- }
-
- /**
- * @return Whether the sim state is ok, meaning we don't need to show
- * a special screen with the emergency call button and keep them from
- * doing anything else.
- */
- private boolean isSimOk(SimCard.State simState) {
- boolean missingAndNotProvisioned = (!mUpdateMonitor.isDeviceProvisioned()
- && simState == SimCard.State.ABSENT);
- return !(missingAndNotProvisioned || simState == SimCard.State.PUK_REQUIRED);
- }
-
- public void onOrientationChange(boolean inPortrait) {
- }
-
- public void onKeyboardChange(boolean isKeyboardOpen) {
- if (isKeyboardOpen) {
- mCallback.goToUnlockScreen();
- }
- }
-
-
- /** {@inheritDoc} */
- public boolean needsInput() {
- return false;
- }
-
- /** {@inheritDoc} */
- public void onPause() {
-
- }
-
- /** {@inheritDoc} */
- public void onResume() {
-
- }
-
- /** {@inheritDoc} */
- public void cleanUp() {
- mUpdateMonitor.removeCallback(this);
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import java.util.Map;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.LayoutInflater;
-
-public class PhoneLayoutInflater extends LayoutInflater {
- private static final String[] sClassPrefixList = {
- "android.widget.",
- "android.webkit."
- };
-
- /**
- * Instead of instantiating directly, you should retrieve an instance
- * through {@link Context#getSystemService}
- *
- * @param context The Context in which in which to find resources and other
- * application-specific things.
- *
- * @see Context#getSystemService
- */
- public PhoneLayoutInflater(Context context) {
- super(context);
- }
-
- protected PhoneLayoutInflater(LayoutInflater original, Context newContext) {
- super(original, newContext);
- }
-
- /** Override onCreateView to instantiate names that correspond to the
- widgets known to the Widget factory. If we don't find a match,
- call through to our super class.
- */
- @Override protected View onCreateView(String name, AttributeSet attrs) throws ClassNotFoundException {
- for (String prefix : sClassPrefixList) {
- try {
- View view = createView(name, prefix, attrs);
- if (view != null) {
- return view;
- }
- } catch (ClassNotFoundException e) {
- // In this case we want to let the base class take a crack
- // at it.
- }
- }
-
- return super.onCreateView(name, attrs);
- }
-
- public LayoutInflater cloneInContext(Context newContext) {
- return new PhoneLayoutInflater(this, newContext);
- }
-}
-
+++ /dev/null
-/*
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import com.android.internal.view.menu.ContextMenuBuilder;
-import com.android.internal.view.menu.MenuBuilder;
-import com.android.internal.view.menu.MenuDialogHelper;
-import com.android.internal.view.menu.MenuView;
-import com.android.internal.view.menu.SubMenuBuilder;
-
-import android.app.KeyguardManager;
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Configuration;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.media.AudioManager;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.SystemClock;
-import android.util.AndroidRuntimeException;
-import android.util.Config;
-import android.util.EventLog;
-import android.util.Log;
-import android.util.SparseArray;
-import android.view.Gravity;
-import android.view.HapticFeedbackConstants;
-import android.view.KeyCharacterMap;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import static android.view.ViewGroup.LayoutParams.FILL_PARENT;
-import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import android.view.ViewManager;
-import android.view.VolumePanel;
-import android.view.Window;
-import android.view.WindowManager;
-import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
-import android.view.animation.Animation;
-import android.view.animation.AnimationUtils;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-
-/**
- * Android-specific Window.
- * <p>
- * todo: need to pull the generic functionality out into a base class
- * in android.widget.
- */
-public class PhoneWindow extends Window implements MenuBuilder.Callback {
- private final static String TAG = "PhoneWindow";
-
- private final static boolean SWEEP_OPEN_MENU = false;
-
- /**
- * Simple callback used by the context menu and its submenus. The options
- * menu submenus do not use this (their behavior is more complex).
- */
- ContextMenuCallback mContextMenuCallback = new ContextMenuCallback(FEATURE_CONTEXT_MENU);
-
- // This is the top-level view of the window, containing the window decor.
- private DecorView mDecor;
-
- // This is the view in which the window contents are placed. It is either
- // mDecor itself, or a child of mDecor where the contents go.
- private ViewGroup mContentParent;
-
- private boolean mIsFloating;
-
- private LayoutInflater mLayoutInflater;
-
- private TextView mTitleView;
-
- private DrawableFeatureState[] mDrawables;
-
- private PanelFeatureState[] mPanels;
-
- /**
- * The panel that is prepared or opened (the most recent one if there are
- * multiple panels). Shortcuts will go to this panel. It gets set in
- * {@link #preparePanel} and cleared in {@link #closePanel}.
- */
- private PanelFeatureState mPreparedPanel;
-
- /**
- * The keycode that is currently held down (as a modifier) for chording. If
- * this is 0, there is no key held down.
- */
- private int mPanelChordingKey;
-
- private ImageView mLeftIconView;
-
- private ImageView mRightIconView;
-
- private ProgressBar mCircularProgressBar;
-
- private ProgressBar mHorizontalProgressBar;
-
- private int mBackgroundResource = 0;
-
- private Drawable mBackgroundDrawable;
-
- private int mFrameResource = 0;
-
- private int mTextColor = 0;
-
- private CharSequence mTitle = null;
-
- private int mTitleColor = 0;
-
- private ContextMenuBuilder mContextMenu;
- private MenuDialogHelper mContextMenuHelper;
-
- private int mVolumeControlStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE;
- private long mVolumeKeyUpTime;
-
- private KeyguardManager mKeyguardManager = null;
-
- private boolean mSearchKeyDownReceived;
-
- private boolean mKeycodeCallTimeoutActive = false;
-
- private boolean mKeycodeCameraTimeoutActive = false;
-
- static final int MSG_MENU_LONG_PRESS = 1;
- static final int MSG_CALL_LONG_PRESS = 2;
- static final int MSG_CAMERA_LONG_PRESS = 3;
-
- private final Handler mKeycodeMenuTimeoutHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_MENU_LONG_PRESS: {
- if (mPanelChordingKey == 0) return;
- mPanelChordingKey = 0;
- mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
- InputMethodManager imm = (InputMethodManager)
- getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
- if (imm != null) {
- imm.showSoftInputUnchecked(InputMethodManager.SHOW_FORCED);
- }
- } break;
- case MSG_CALL_LONG_PRESS: {
- if (!mKeycodeCallTimeoutActive) return;
- mKeycodeCallTimeoutActive = false;
- mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
- // launch the VoiceDialer
- Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- try {
- sendCloseSystemWindows();
- getContext().startActivity(intent);
- } catch (ActivityNotFoundException e) {
- startCallActivity();
- }
- } break;
- case MSG_CAMERA_LONG_PRESS: {
- if (!mKeycodeCameraTimeoutActive) return;
- mKeycodeCameraTimeoutActive = false;
- mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
- // Broadcast an intent that the Camera button was longpressed
- Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null);
- intent.putExtra(Intent.EXTRA_KEY_EVENT, (KeyEvent) msg.obj);
- getContext().sendOrderedBroadcast(intent, null);
- } break;
- }
- }
- };
-
- public PhoneWindow(Context context) {
- super(context);
- mLayoutInflater = LayoutInflater.from(context);
- }
-
- @Override
- public final void setContainer(Window container) {
- super.setContainer(container);
- }
-
- @Override
- public boolean requestFeature(int featureId) {
- if (mContentParent != null) {
- throw new AndroidRuntimeException("requestFeature() must be called before adding content");
- }
- final int features = getFeatures();
- if ((features != DEFAULT_FEATURES) && (featureId == FEATURE_CUSTOM_TITLE)) {
-
- /* Another feature is enabled and the user is trying to enable the custom title feature */
- throw new AndroidRuntimeException("You cannot combine custom titles with other title features");
- }
- if (((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) && (featureId != FEATURE_CUSTOM_TITLE)) {
-
- /* Custom title feature is enabled and the user is trying to enable another feature */
- throw new AndroidRuntimeException("You cannot combine custom titles with other title features");
- }
- /* FEATURE_OPENGL disabled for 1.0
- if (featureId == FEATURE_OPENGL) {
- getAttributes().memoryType = WindowManager.LayoutParams.MEMORY_TYPE_GPU;
- }
- */
- return super.requestFeature(featureId);
- }
-
- @Override
- public void setContentView(int layoutResID) {
- if (mContentParent == null) {
- installDecor();
- } else {
- mContentParent.removeAllViews();
- }
- mLayoutInflater.inflate(layoutResID, mContentParent);
- final Callback cb = getCallback();
- if (cb != null) {
- cb.onContentChanged();
- }
- }
-
- @Override
- public void setContentView(View view) {
- setContentView(view, new ViewGroup.LayoutParams(FILL_PARENT, FILL_PARENT));
- }
-
- @Override
- public void setContentView(View view, ViewGroup.LayoutParams params) {
- if (mContentParent == null) {
- installDecor();
- } else {
- mContentParent.removeAllViews();
- }
- mContentParent.addView(view, params);
- final Callback cb = getCallback();
- if (cb != null) {
- cb.onContentChanged();
- }
- }
-
- @Override
- public void addContentView(View view, ViewGroup.LayoutParams params) {
- if (mContentParent == null) {
- installDecor();
- }
- mContentParent.addView(view, params);
- final Callback cb = getCallback();
- if (cb != null) {
- cb.onContentChanged();
- }
- }
-
- @Override
- public View getCurrentFocus() {
- return mDecor != null ? mDecor.findFocus() : null;
- }
-
- @Override
- public boolean isFloating() {
- return mIsFloating;
- }
-
- /**
- * Return a LayoutInflater instance that can be used to inflate XML view layout
- * resources for use in this Window.
- *
- * @return LayoutInflater The shared LayoutInflater.
- */
- @Override
- public LayoutInflater getLayoutInflater() {
- return mLayoutInflater;
- }
-
- @Override
- public void setTitle(CharSequence title) {
- if (mTitleView != null) {
- mTitleView.setText(title);
- }
- mTitle = title;
- }
-
- @Override
- public void setTitleColor(int textColor) {
- if (mTitleView != null) {
- mTitleView.setTextColor(textColor);
- }
- mTitleColor = textColor;
- }
-
- /**
- * Prepares the panel to either be opened or chorded. This creates the Menu
- * instance for the panel and populates it via the Activity callbacks.
- *
- * @param st The panel state to prepare.
- * @param event The event that triggered the preparing of the panel.
- * @return Whether the panel was prepared. If the panel should not be shown,
- * returns false.
- */
- public final boolean preparePanel(PanelFeatureState st, KeyEvent event) {
- // Already prepared (isPrepared will be reset to false later)
- if (st.isPrepared)
- return true;
-
- if ((mPreparedPanel != null) && (mPreparedPanel != st)) {
- // Another Panel is prepared and possibly open, so close it
- closePanel(mPreparedPanel, false);
- }
-
- final Callback cb = getCallback();
-
- 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 (!initializePanelMenu(st) || (st.menu == null)) {
- return false;
- }
- // Call callback, and return if it doesn't want to display menu
- 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;
- st.menu.setQwertyMode(st.qwertyMode);
- }
-
- // Set other state
- st.isPrepared = true;
- st.isHandled = false;
- mPreparedPanel = st;
-
- return true;
- }
-
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- 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();
- menuBuilder.saveHierarchyState(state);
-
- // Remove the menu views since they need to be recreated
- // according to the new configuration
- clearMenuViews(st);
-
- // Re-open the same menu
- reopenMenu(false);
-
- // Restore state
- menuBuilder.restoreHierarchyState(state);
-
- } else {
- // Clear menu views so on next menu opening, it will use
- // the proper layout
- 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
- st.refreshDecorView = true;
-
- ((MenuBuilder) st.menu).clearMenuViews();
- }
-
- @Override
- public final void openPanel(int featureId, KeyEvent event) {
- openPanel(getPanelState(featureId, true), event);
- }
-
- private void openPanel(PanelFeatureState st, KeyEvent event) {
- // System.out.println("Open panel: isOpen=" + st.isOpen);
-
- // Already open, return
- if (st.isOpen) {
- return;
- }
-
- Callback cb = getCallback();
- if ((cb != null) && (!cb.onMenuOpened(st.featureId, st.menu))) {
- // Callback doesn't want the menu to open, reset any state
- closePanel(st, true);
- return;
- }
-
- final WindowManager wm = getWindowManager();
- if (wm == null) {
- return;
- }
-
- // Prepare panel (should have been done before, but just in case)
- if (!preparePanel(st, event)) {
- return;
- }
-
- if (st.decorView == null || st.refreshDecorView) {
- if (st.decorView == null) {
- // Initialize the panel decor, this will populate st.decorView
- if (!initializePanelDecor(st) || (st.decorView == null))
- return;
- } else if (st.refreshDecorView && (st.decorView.getChildCount() > 0)) {
- // Decor needs refreshing, so remove its views
- st.decorView.removeAllViews();
- }
-
- // This will populate st.shownPanelView
- if (!initializePanelContent(st) || (st.shownPanelView == null)) {
- return;
- }
-
- ViewGroup.LayoutParams lp = st.shownPanelView.getLayoutParams();
- if (lp == null) {
- lp = new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
- }
-
- int backgroundResId;
- if (lp.width == ViewGroup.LayoutParams.FILL_PARENT) {
- // If the contents is fill parent for the width, set the
- // corresponding background
- backgroundResId = st.fullBackground;
- } else {
- // Otherwise, set the normal panel background
- backgroundResId = st.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.
- */
- if (!st.shownPanelView.hasFocus()) {
- st.shownPanelView.requestFocus();
- }
- }
-
- st.isOpen = true;
- st.isHandled = false;
-
- WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- WRAP_CONTENT, WRAP_CONTENT,
- st.x, st.y, WindowManager.LayoutParams.TYPE_APPLICATION_PANEL,
- WindowManager.LayoutParams.FLAG_DITHER
- | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
- st.decorView.mDefaultOpacity);
-
- lp.gravity = st.gravity;
- lp.windowAnimations = st.windowAnimations;
- wm.addView(st.decorView, lp);
- // Log.v(TAG, "Adding main menu to window manager.");
- }
-
- @Override
- public final void closePanel(int featureId) {
- if (featureId == FEATURE_CONTEXT_MENU) {
- closeContextMenu();
- } else {
- closePanel(getPanelState(featureId, true), true);
- }
- }
-
- /**
- * Closes the given panel.
- *
- * @param st The panel to be closed.
- * @param doCallback Whether to notify the callback that the panel was
- * closed. If the panel is in the process of re-opening or
- * opening another panel (e.g., menu opening a sub menu), the
- * callback should not happen and this variable should be false.
- * In addition, this method internally will only perform the
- * callback if the panel is open.
- */
- public final void closePanel(PanelFeatureState st, boolean doCallback) {
- // System.out.println("Close panel: isOpen=" + st.isOpen);
- final ViewManager wm = getWindowManager();
- if ((wm != null) && st.isOpen) {
- if (st.decorView != null) {
- wm.removeView(st.decorView);
- // Log.v(TAG, "Removing main menu from window manager.");
- }
-
- if (doCallback) {
- callOnPanelClosed(st.featureId, st, null);
- }
- }
- st.isPrepared = false;
- st.isHandled = false;
- st.isOpen = false;
-
- // 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
- st.refreshDecorView = true;
- st.isInExpandedMode = false;
- }
-
- if (mPreparedPanel == st) {
- mPreparedPanel = null;
- mPanelChordingKey = 0;
- }
- }
-
- @Override
- public final void togglePanel(int featureId, KeyEvent event) {
- PanelFeatureState st = getPanelState(featureId, true);
- if (st.isOpen) {
- closePanel(st, true);
- } else {
- openPanel(st, event);
- }
- }
-
- /**
- * Called when the panel key is pushed down.
- * @param featureId The feature ID of the relevant panel (defaults to FEATURE_OPTIONS_PANEL}.
- * @param event The key event.
- * @return Whether the key was handled.
- */
- public final boolean onKeyDownPanel(int featureId, KeyEvent event) {
- // The panel key was pushed, so set the chording key
- mPanelChordingKey = event.getKeyCode();
-
- PanelFeatureState st = getPanelState(featureId, true);
- if (!st.isOpen) {
- if (getContext().getResources().getConfiguration().keyboard
- == Configuration.KEYBOARD_NOKEYS) {
- mKeycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS);
- mKeycodeMenuTimeoutHandler.sendMessageDelayed(
- mKeycodeMenuTimeoutHandler.obtainMessage(MSG_MENU_LONG_PRESS),
- ViewConfiguration.getLongPressTimeout());
- }
- return preparePanel(st, event);
- }
-
- return false;
- }
-
- /**
- * Called when the panel key is released.
- * @param featureId The feature ID of the relevant panel (defaults to FEATURE_OPTIONS_PANEL}.
- * @param event The key event.
- */
- public final void onKeyUpPanel(int featureId, KeyEvent event) {
- // The panel key was released, so clear the chording key
- 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);
- if (audioManager != null) {
- audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
- } else {
- Log.w(TAG, "Couldn't get audio manager");
- }
- }
- }
- }
-
- @Override
- public final void closeAllPanels() {
- final ViewManager wm = getWindowManager();
- if (wm == null) {
- return;
- }
-
- final PanelFeatureState[] panels = mPanels;
- final int N = panels != null ? panels.length : 0;
- for (int i = 0; i < N; i++) {
- final PanelFeatureState panel = panels[i];
- if (panel != null) {
- closePanel(panel, true);
- }
- }
-
- closeContextMenu();
- }
-
- /**
- * Closes the context menu. This notifies the menu logic of the close, along
- * with dismissing it from the UI.
- */
- private synchronized void closeContextMenu() {
- if (mContextMenu != null) {
- mContextMenu.close();
- dismissContextMenu();
- }
- }
-
- /**
- * Dismisses just the context menu UI. To close the context menu, use
- * {@link #closeContextMenu()}.
- */
- private synchronized void dismissContextMenu() {
- mContextMenu = null;
-
- if (mContextMenuHelper != null) {
- mContextMenuHelper.dismiss();
- mContextMenuHelper = null;
- }
- }
-
- @Override
- public boolean performPanelShortcut(int featureId, int keyCode, KeyEvent event, int flags) {
- return performPanelShortcut(getPanelState(featureId, true), keyCode, event, flags);
- }
-
- private boolean performPanelShortcut(PanelFeatureState st, int keyCode, KeyEvent event,
- int flags) {
- if (event.isSystem() || (st == null)) {
- return false;
- }
-
- boolean handled = false;
-
- // Only try to perform menu shortcuts if preparePanel returned true (possible false
- // return value from application not wanting to show the menu).
- if ((st.isPrepared || preparePanel(st, event)) && st.menu != null) {
- // The menu is prepared now, perform the shortcut on it
- handled = st.menu.performShortcut(keyCode, event, flags);
- }
-
- if (handled) {
- // Mark as handled
- st.isHandled = true;
-
- if ((flags & Menu.FLAG_PERFORM_NO_CLOSE) == 0) {
- closePanel(st, true);
- }
- }
-
- return handled;
- }
-
- @Override
- public boolean performPanelIdentifierAction(int featureId, int id, int flags) {
-
- PanelFeatureState st = getPanelState(featureId, true);
- if (!preparePanel(st, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU))) {
- return false;
- }
- if (st.menu == null) {
- return false;
- }
-
- boolean res = st.menu.performIdentifierAction(id, flags);
-
- closePanel(st, true);
-
- return res;
- }
-
- public PanelFeatureState findMenuPanel(Menu menu) {
- final PanelFeatureState[] panels = mPanels;
- final int N = panels != null ? panels.length : 0;
- for (int i = 0; i < N; i++) {
- final PanelFeatureState panel = panels[i];
- if (panel != null && panel.menu == menu) {
- return panel;
- }
- }
- return null;
- }
-
- public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
- final Callback cb = getCallback();
- if (cb != null) {
- final PanelFeatureState panel = findMenuPanel(menu.getRootMenu());
- if (panel != null) {
- return cb.onMenuItemSelected(panel.featureId, item);
- }
- }
- return false;
- }
-
- public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
- final PanelFeatureState panel = findMenuPanel(menu);
- if (panel != null) {
- // Close the panel and only do the callback if the menu is being
- // closed
- // completely, not if opening a sub menu
- closePanel(panel, allMenusAreClosing);
- }
- }
-
- public void onCloseSubMenu(SubMenuBuilder subMenu) {
- final Menu parentMenu = subMenu.getRootMenu();
- final PanelFeatureState panel = findMenuPanel(parentMenu);
-
- // Callback
- if (panel != null) {
- callOnPanelClosed(panel.featureId, panel, parentMenu);
- closePanel(panel, true);
- }
- }
-
- public boolean onSubMenuSelected(final SubMenuBuilder subMenu) {
- if (!subMenu.hasVisibleItems()) {
- return true;
- }
-
- // The window manager will give us a valid window token
- new MenuDialogHelper(subMenu).show(null);
-
- return true;
- }
-
- public void onMenuModeChange(MenuBuilder menu) {
- reopenMenu(true);
- }
-
- private void reopenMenu(boolean toggleMenuMode) {
- PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true);
-
- // Save the future expanded mode state since closePanel will reset it
- boolean newExpandedMode = toggleMenuMode ? !st.isInExpandedMode : st.isInExpandedMode;
-
- st.refreshDecorView = true;
- closePanel(st, false);
-
- // Set the expanded mode state
- st.isInExpandedMode = newExpandedMode;
-
- openPanel(st, null);
- }
-
- /**
- * Initializes the menu associated with the given panel feature state. You
- * must at the very least set PanelFeatureState.menu to the Menu to be
- * associated with the given panel state. The default implementation creates
- * a new menu for the panel state.
- *
- * @param st The panel whose menu is being initialized.
- * @return Whether the initialization was successful.
- */
- protected boolean initializePanelMenu(final PanelFeatureState st) {
- final MenuBuilder menu = new MenuBuilder(getContext());
-
- menu.setCallback(this);
- st.setMenu(menu);
-
- return true;
- }
-
- /**
- * Perform initial setup of a panel. This should at the very least set the
- * style information in the PanelFeatureState and must set
- * PanelFeatureState.decor to the panel's window decor view.
- *
- * @param st The panel being initialized.
- */
- protected boolean initializePanelDecor(PanelFeatureState st) {
- st.decorView = new DecorView(getContext(), st.featureId);
- st.gravity = Gravity.CENTER | Gravity.BOTTOM;
- st.setStyle(getContext());
-
- return true;
- }
-
- /**
- * Initializes the panel associated with the panel feature state. You must
- * at the very least set PanelFeatureState.panel to the View implementing
- * its contents. The default implementation gets the panel from the menu.
- *
- * @param st The panel state being initialized.
- * @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;
- }
-
- st.shownPanelView = menu.getMenuView((st.isInExpandedMode) ? MenuBuilder.TYPE_EXPANDED
- : MenuBuilder.TYPE_ICON, st.decorView);
-
- if (st.shownPanelView != null) {
- // Use the menu View's default animations if it has any
- final int defaultAnimations = ((MenuView) st.shownPanelView).getWindowAnimations();
- if (defaultAnimations != 0) {
- st.windowAnimations = defaultAnimations;
- }
- return true;
- } else {
- return false;
- }
- }
-
- @Override
- public boolean performContextMenuIdentifierAction(int id, int flags) {
- return (mContextMenu != null) ? mContextMenu.performIdentifierAction(id, flags) : false;
- }
-
- @Override
- public final void setBackgroundDrawable(Drawable drawable) {
- if (drawable != mBackgroundDrawable) {
- mBackgroundResource = 0;
- mBackgroundDrawable = drawable;
- if (mDecor != null) {
- mDecor.setWindowBackground(drawable);
- }
- }
- }
-
- @Override
- public final void setFeatureDrawableResource(int featureId, int resId) {
- if (resId != 0) {
- DrawableFeatureState st = getDrawableState(featureId, true);
- if (st.resid != resId) {
- st.resid = resId;
- st.uri = null;
- st.local = getContext().getResources().getDrawable(resId);
- updateDrawable(featureId, st, false);
- }
- } else {
- setFeatureDrawable(featureId, null);
- }
- }
-
- @Override
- public final void setFeatureDrawableUri(int featureId, Uri uri) {
- if (uri != null) {
- DrawableFeatureState st = getDrawableState(featureId, true);
- if (st.uri == null || !st.uri.equals(uri)) {
- st.resid = 0;
- st.uri = uri;
- st.local = loadImageURI(uri);
- updateDrawable(featureId, st, false);
- }
- } else {
- setFeatureDrawable(featureId, null);
- }
- }
-
- @Override
- public final void setFeatureDrawable(int featureId, Drawable drawable) {
- DrawableFeatureState st = getDrawableState(featureId, true);
- st.resid = 0;
- st.uri = null;
- if (st.local != drawable) {
- st.local = drawable;
- updateDrawable(featureId, st, false);
- }
- }
-
- @Override
- public void setFeatureDrawableAlpha(int featureId, int alpha) {
- DrawableFeatureState st = getDrawableState(featureId, true);
- if (st.alpha != alpha) {
- st.alpha = alpha;
- updateDrawable(featureId, st, false);
- }
- }
-
- protected final void setFeatureDefaultDrawable(int featureId, Drawable drawable) {
- DrawableFeatureState st = getDrawableState(featureId, true);
- if (st.def != drawable) {
- st.def = drawable;
- updateDrawable(featureId, st, false);
- }
- }
-
- @Override
- public final void setFeatureInt(int featureId, int value) {
- // XXX Should do more management (as with drawable features) to
- // deal with interactions between multiple window policies.
- updateInt(featureId, value, false);
- }
-
- /**
- * Update the state of a drawable feature. This should be called, for every
- * drawable feature supported, as part of onActive(), to make sure that the
- * contents of a containing window is properly updated.
- *
- * @see #onActive
- * @param featureId The desired drawable feature to change.
- * @param fromActive Always true when called from onActive().
- */
- protected final void updateDrawable(int featureId, boolean fromActive) {
- final DrawableFeatureState st = getDrawableState(featureId, false);
- if (st != null) {
- updateDrawable(featureId, st, fromActive);
- }
- }
-
- /**
- * Called when a Drawable feature changes, for the window to update its
- * graphics.
- *
- * @param featureId The feature being changed.
- * @param drawable The new Drawable to show, or null if none.
- * @param alpha The new alpha blending of the Drawable.
- */
- protected void onDrawableChanged(int featureId, Drawable drawable, int alpha) {
- ImageView view;
- if (featureId == FEATURE_LEFT_ICON) {
- view = getLeftIconView();
- } else if (featureId == FEATURE_RIGHT_ICON) {
- view = getRightIconView();
- } else {
- return;
- }
-
- if (drawable != null) {
- drawable.setAlpha(alpha);
- view.setImageDrawable(drawable);
- view.setVisibility(View.VISIBLE);
- } else {
- view.setVisibility(View.GONE);
- }
- }
-
- /**
- * Called when an int feature changes, for the window to update its
- * graphics.
- *
- * @param featureId The feature being changed.
- * @param value The new integer value.
- */
- protected void onIntChanged(int featureId, int value) {
- if (featureId == FEATURE_PROGRESS || featureId == FEATURE_INDETERMINATE_PROGRESS) {
- updateProgressBars(value);
- } else if (featureId == FEATURE_CUSTOM_TITLE) {
- FrameLayout titleContainer = (FrameLayout) findViewById(com.android.internal.R.id.title_container);
- if (titleContainer != null) {
- mLayoutInflater.inflate(value, titleContainer);
- }
- }
- }
-
- /**
- * Updates the progress bars that are shown in the title bar.
- *
- * @param value Can be one of {@link Window#PROGRESS_VISIBILITY_ON},
- * {@link Window#PROGRESS_VISIBILITY_OFF},
- * {@link Window#PROGRESS_INDETERMINATE_ON},
- * {@link Window#PROGRESS_INDETERMINATE_OFF}, or a value
- * starting at {@link Window#PROGRESS_START} through
- * {@link Window#PROGRESS_END} for setting the default
- * progress (if {@link Window#PROGRESS_END} is given,
- * the progress bar widgets in the title will be hidden after an
- * animation), a value between
- * {@link Window#PROGRESS_SECONDARY_START} -
- * {@link Window#PROGRESS_SECONDARY_END} for the
- * secondary progress (if
- * {@link Window#PROGRESS_SECONDARY_END} is given, the
- * progress bar widgets will still be shown with the secondary
- * progress bar will be completely filled in.)
- */
- private void updateProgressBars(int value) {
- ProgressBar circularProgressBar = getCircularProgressBar(true);
- ProgressBar horizontalProgressBar = getHorizontalProgressBar(true);
-
- final int features = getLocalFeatures();
- if (value == PROGRESS_VISIBILITY_ON) {
- if ((features & (1 << FEATURE_PROGRESS)) != 0) {
- int level = horizontalProgressBar.getProgress();
- int visibility = (horizontalProgressBar.isIndeterminate() || level < 10000) ?
- View.VISIBLE : View.INVISIBLE;
- horizontalProgressBar.setVisibility(visibility);
- }
- if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {
- circularProgressBar.setVisibility(View.VISIBLE);
- }
- } else if (value == PROGRESS_VISIBILITY_OFF) {
- if ((features & (1 << FEATURE_PROGRESS)) != 0) {
- horizontalProgressBar.setVisibility(View.GONE);
- }
- if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {
- circularProgressBar.setVisibility(View.GONE);
- }
- } else if (value == PROGRESS_INDETERMINATE_ON) {
- horizontalProgressBar.setIndeterminate(true);
- } else if (value == PROGRESS_INDETERMINATE_OFF) {
- horizontalProgressBar.setIndeterminate(false);
- } else if (PROGRESS_START <= value && value <= PROGRESS_END) {
- // We want to set the progress value before testing for visibility
- // so that when the progress bar becomes visible again, it has the
- // correct level.
- horizontalProgressBar.setProgress(value - PROGRESS_START);
-
- if (value < PROGRESS_END) {
- showProgressBars(horizontalProgressBar, circularProgressBar);
- } else {
- hideProgressBars(horizontalProgressBar, circularProgressBar);
- }
- } else if (PROGRESS_SECONDARY_START <= value && value <= PROGRESS_SECONDARY_END) {
- horizontalProgressBar.setSecondaryProgress(value - PROGRESS_SECONDARY_START);
-
- showProgressBars(horizontalProgressBar, circularProgressBar);
- }
-
- }
-
- private void showProgressBars(ProgressBar horizontalProgressBar, ProgressBar spinnyProgressBar) {
- final int features = getLocalFeatures();
- if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0 &&
- spinnyProgressBar.getVisibility() == View.INVISIBLE) {
- spinnyProgressBar.setVisibility(View.VISIBLE);
- }
- // Only show the progress bars if the primary progress is not complete
- if ((features & (1 << FEATURE_PROGRESS)) != 0 &&
- horizontalProgressBar.getProgress() < 10000) {
- horizontalProgressBar.setVisibility(View.VISIBLE);
- }
- }
-
- private void hideProgressBars(ProgressBar horizontalProgressBar, ProgressBar spinnyProgressBar) {
- final int features = getLocalFeatures();
- Animation anim = AnimationUtils.loadAnimation(getContext(), com.android.internal.R.anim.fade_out);
- anim.setDuration(1000);
- if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0 &&
- spinnyProgressBar.getVisibility() == View.VISIBLE) {
- spinnyProgressBar.startAnimation(anim);
- spinnyProgressBar.setVisibility(View.INVISIBLE);
- }
- if ((features & (1 << FEATURE_PROGRESS)) != 0 &&
- horizontalProgressBar.getVisibility() == View.VISIBLE) {
- horizontalProgressBar.startAnimation(anim);
- horizontalProgressBar.setVisibility(View.INVISIBLE);
- }
- }
-
- /**
- * Request that key events come to this activity. Use this if your activity
- * has no views with focus, but the activity still wants a chance to process
- * key events.
- */
- @Override
- public void takeKeyEvents(boolean get) {
- mDecor.setFocusable(get);
- }
-
- @Override
- public boolean superDispatchKeyEvent(KeyEvent event) {
- return mDecor.superDispatchKeyEvent(event);
- }
-
- @Override
- public boolean superDispatchTouchEvent(MotionEvent event) {
- return mDecor.superDispatchTouchEvent(event);
- }
-
- @Override
- public boolean superDispatchTrackballEvent(MotionEvent event) {
- return mDecor.superDispatchTrackballEvent(event);
- }
-
- /**
- * A key was pressed down and not handled by anything else in the window.
- *
- * @see #onKeyUp
- * @see android.view.KeyEvent
- */
- protected boolean onKeyDown(int featureId, int keyCode, KeyEvent event) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_VOLUME_UP:
- case KeyEvent.KEYCODE_VOLUME_DOWN: {
- AudioManager audioManager = (AudioManager) getContext().getSystemService(
- Context.AUDIO_SERVICE);
- if (audioManager != null) {
- /*
- * Adjust the volume in on key down since it is more
- * responsive to the user.
- */
- audioManager.adjustSuggestedStreamVolume(
- keyCode == KeyEvent.KEYCODE_VOLUME_UP
- ? AudioManager.ADJUST_RAISE
- : AudioManager.ADJUST_LOWER,
- mVolumeControlStreamType,
- AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE);
- }
- return true;
- }
-
- case KeyEvent.KEYCODE_MUTE:
- 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);
- getContext().sendOrderedBroadcast(intent, null);
- return true;
- }
-
- case KeyEvent.KEYCODE_CAMERA: {
- if (getKeyguardManager().inKeyguardRestrictedInputMode()) {
- break;
- }
- if (event.getRepeatCount() > 0) break;
- mKeycodeCameraTimeoutActive = true;
- mKeycodeMenuTimeoutHandler.removeMessages(MSG_CAMERA_LONG_PRESS);
- Message message = mKeycodeMenuTimeoutHandler.obtainMessage(MSG_CAMERA_LONG_PRESS);
- message.obj = event;
- mKeycodeMenuTimeoutHandler.sendMessageDelayed(message,
- ViewConfiguration.getLongPressTimeout());
- return true;
- }
-
- case KeyEvent.KEYCODE_MENU: {
- if (event.getRepeatCount() > 0) break;
- onKeyDownPanel((featureId < 0) ? FEATURE_OPTIONS_PANEL : featureId, event);
- return true;
- }
-
- case KeyEvent.KEYCODE_BACK: {
- if (event.getRepeatCount() > 0) break;
- if (featureId < 0) break;
- if (featureId == FEATURE_OPTIONS_PANEL) {
- PanelFeatureState st = getPanelState(featureId, false);
- if (st != null && st.isInExpandedMode) {
- // If the user is in an expanded menu and hits back, it
- // should go back to the icon menu
- reopenMenu(true);
- return true;
- }
- }
- closePanel(featureId);
- return true;
- }
-
- case KeyEvent.KEYCODE_CALL: {
- if (getKeyguardManager().inKeyguardRestrictedInputMode()) {
- break;
- }
- if (event.getRepeatCount() > 0) break;
- mKeycodeCallTimeoutActive = true;
- mKeycodeMenuTimeoutHandler.removeMessages(MSG_CALL_LONG_PRESS);
- mKeycodeMenuTimeoutHandler.sendMessageDelayed(
- mKeycodeMenuTimeoutHandler.obtainMessage(MSG_CALL_LONG_PRESS),
- ViewConfiguration.getLongPressTimeout());
- return true;
- }
-
- case KeyEvent.KEYCODE_SEARCH: {
- if (event.getRepeatCount() == 0) {
- mSearchKeyDownReceived = true;
- }
- break;
- }
- }
-
- return false;
- }
-
- /**
- * @return A handle to the keyguard manager.
- */
- private KeyguardManager getKeyguardManager() {
- if (mKeyguardManager == null) {
- mKeyguardManager = (KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE);
- }
- return mKeyguardManager;
- }
-
- /**
- * A key was released and not handled by anything else in the window.
- *
- * @see #onKeyDown
- * @see android.view.KeyEvent
- */
- protected boolean onKeyUp(int featureId, int keyCode, KeyEvent event) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_VOLUME_UP:
- case KeyEvent.KEYCODE_VOLUME_DOWN: {
- AudioManager audioManager = (AudioManager) getContext().getSystemService(
- Context.AUDIO_SERVICE);
- if (audioManager != null) {
- /*
- * Play a sound. This is done on key up since we don't want the
- * sound to play when a user holds down volume down to mute.
- */
- audioManager.adjustSuggestedStreamVolume(
- AudioManager.ADJUST_SAME,
- mVolumeControlStreamType,
- AudioManager.FLAG_PLAY_SOUND);
- mVolumeKeyUpTime = SystemClock.uptimeMillis();
- }
- return true;
- }
-
- case KeyEvent.KEYCODE_MENU: {
- onKeyUpPanel(featureId < 0 ? FEATURE_OPTIONS_PANEL : featureId,
- event);
- 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_FORWARD: {
- Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
- intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
- getContext().sendOrderedBroadcast(intent, null);
- return true;
- }
-
- case KeyEvent.KEYCODE_CAMERA: {
- if (getKeyguardManager().inKeyguardRestrictedInputMode()) {
- break;
- }
- if (event.getRepeatCount() > 0) break; // Can a key up event repeat?
- mKeycodeMenuTimeoutHandler.removeMessages(MSG_CAMERA_LONG_PRESS);
- if (!mKeycodeCameraTimeoutActive) break;
- mKeycodeCameraTimeoutActive = false;
- // Add short press behavior here if desired
- return true;
- }
-
- case KeyEvent.KEYCODE_CALL: {
- if (getKeyguardManager().inKeyguardRestrictedInputMode()) {
- break;
- }
- if (event.getRepeatCount() > 0) break;
- mKeycodeMenuTimeoutHandler.removeMessages(MSG_CALL_LONG_PRESS);
- if (!mKeycodeCallTimeoutActive) break;
- mKeycodeCallTimeoutActive = false;
- startCallActivity();
- return true;
- }
-
- case KeyEvent.KEYCODE_SEARCH: {
- /*
- * Do this in onKeyUp since the Search key is also used for
- * chording quick launch shortcuts.
- */
- if (getKeyguardManager().inKeyguardRestrictedInputMode() ||
- !mSearchKeyDownReceived) {
- break;
- }
- mSearchKeyDownReceived = false;
- launchDefaultSearch();
- return true;
- }
- }
-
- return false;
- }
-
- private void startCallActivity() {
- sendCloseSystemWindows();
- Intent intent = new Intent(Intent.ACTION_CALL_BUTTON);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- getContext().startActivity(intent);
- }
-
- @Override
- protected void onActive() {
- }
-
- @Override
- public final View getDecorView() {
- if (mDecor == null) {
- installDecor();
- }
- return mDecor;
- }
-
- @Override
- public final View peekDecorView() {
- return mDecor;
- }
-
- static private final String FOCUSED_ID_TAG = "android:focusedViewId";
- static private final String VIEWS_TAG = "android:views";
- static private final String PANELS_TAG = "android:Panels";
-
- /** {@inheritDoc} */
- @Override
- public Bundle saveHierarchyState() {
- Bundle outState = new Bundle();
- if (mContentParent == null) {
- return outState;
- }
-
- SparseArray<Parcelable> states = new SparseArray<Parcelable>();
- mContentParent.saveHierarchyState(states);
- outState.putSparseParcelableArray(VIEWS_TAG, states);
-
- // save the focused view id
- View focusedView = mContentParent.findFocus();
- if (focusedView != null) {
- if (focusedView.getId() != View.NO_ID) {
- outState.putInt(FOCUSED_ID_TAG, focusedView.getId());
- } else {
- if (Config.LOGD) {
- Log.d(TAG, "couldn't save which view has focus because the focused view "
- + focusedView + " has no id.");
- }
- }
- }
-
- // save the panels
- SparseArray<Parcelable> panelStates = new SparseArray<Parcelable>();
- savePanelState(panelStates);
- if (panelStates.size() > 0) {
- outState.putSparseParcelableArray(PANELS_TAG, panelStates);
- }
-
- return outState;
- }
-
- /** {@inheritDoc} */
- @Override
- public void restoreHierarchyState(Bundle savedInstanceState) {
- if (mContentParent == null) {
- return;
- }
-
- SparseArray<Parcelable> savedStates
- = savedInstanceState.getSparseParcelableArray(VIEWS_TAG);
- if (savedStates != null) {
- mContentParent.restoreHierarchyState(savedStates);
- }
-
- // restore the focused view
- int focusedViewId = savedInstanceState.getInt(FOCUSED_ID_TAG, View.NO_ID);
- if (focusedViewId != View.NO_ID) {
- View needsFocus = mContentParent.findViewById(focusedViewId);
- if (needsFocus != null) {
- needsFocus.requestFocus();
- } else {
- Log.w(TAG,
- "Previously focused view reported id " + focusedViewId
- + " during save, but can't be found during restore.");
- }
- }
-
- // restore the panels
- SparseArray<Parcelable> panelStates = savedInstanceState.getSparseParcelableArray(PANELS_TAG);
- if (panelStates != null) {
- restorePanelState(panelStates);
- }
- }
-
- /**
- * Invoked when the panels should freeze their state.
- *
- * @param icicles Save state into this. This is usually indexed by the
- * featureId. This will be given to {@link #restorePanelState} in the
- * future.
- */
- private void savePanelState(SparseArray<Parcelable> icicles) {
- PanelFeatureState[] panels = mPanels;
- if (panels == null) {
- return;
- }
-
- for (int curFeatureId = panels.length - 1; curFeatureId >= 0; curFeatureId--) {
- if (panels[curFeatureId] != null) {
- icicles.put(curFeatureId, panels[curFeatureId].onSaveInstanceState());
- }
- }
- }
-
- /**
- * Invoked when the panels should thaw their state from a previously frozen state.
- *
- * @param icicles The state saved by {@link #savePanelState} that needs to be thawed.
- */
- private void restorePanelState(SparseArray<Parcelable> icicles) {
- PanelFeatureState st;
- for (int curFeatureId = icicles.size() - 1; curFeatureId >= 0; curFeatureId--) {
- st = getPanelState(curFeatureId, false /* required */);
- if (st == null) {
- // The panel must not have been required, and is currently not around, skip it
- continue;
- }
-
- st.onRestoreInstanceState(icicles.get(curFeatureId));
- }
-
- /*
- * Implementation note: call openPanelsAfterRestore later to actually open the
- * restored panels.
- */
- }
-
- /**
- * Opens the panels that have had their state restored. This should be
- * called sometime after {@link #restorePanelState} when it is safe to add
- * to the window manager.
- */
- private void openPanelsAfterRestore() {
- PanelFeatureState[] panels = mPanels;
-
- if (panels == null) {
- return;
- }
-
- PanelFeatureState st;
- for (int i = panels.length - 1; i >= 0; i--) {
- st = panels[i];
- if ((st != null) && st.isOpen) {
- // Clear st.isOpen (openPanel will not open if it's already open)
- st.isOpen = false;
- openPanel(st, null);
- }
- }
- }
-
- private final class DecorView extends FrameLayout {
- /* package */int mDefaultOpacity = PixelFormat.OPAQUE;
-
- /** The feature ID of the panel, or -1 if this is the application's DecorView */
- private final int mFeatureId;
-
- private final Rect mDrawingBounds = new Rect();
-
- private final Rect mBackgroundPadding = new Rect();
-
- private final Rect mFramePadding = new Rect();
-
- private final Rect mFrameOffsets = new Rect();
-
- private final Paint mBlackPaint = new Paint();
-
- private boolean mChanging;
-
- private Drawable mMenuBackground;
- private boolean mWatchingForMenu;
- private int mDownY;
-
- public DecorView(Context context, int featureId) {
- super(context);
- mFeatureId = featureId;
- mBlackPaint.setColor(0xFF000000);
- }
-
- @Override
- public boolean dispatchKeyEvent(KeyEvent event) {
- final int keyCode = event.getKeyCode();
- final boolean isDown = event.getAction() == KeyEvent.ACTION_DOWN;
-
- /*
- * If the user hits another key within the play sound delay, then
- * cancel the sound
- */
- if (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_VOLUME_UP
- && mVolumeKeyUpTime + VolumePanel.PLAY_SOUND_DELAY
- > SystemClock.uptimeMillis()) {
- /*
- * The user has hit another key during the delay (e.g., 300ms)
- * since the last volume key up, so cancel any sounds.
- */
- AudioManager audioManager = (AudioManager) getContext().getSystemService(
- Context.AUDIO_SERVICE);
- if (audioManager != null) {
- audioManager.adjustSuggestedStreamVolume(AudioManager.ADJUST_SAME,
- 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.
- if ((mPanelChordingKey > 0) && (mPanelChordingKey != keyCode)) {
- // Perform the shortcut (mPreparedPanel can be null since
- // global shortcuts (such as search) don't rely on a
- // 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
- * and anyone else that may be interested.
- */
- handled = dispatchKeyShortcutEvent(event);
-
- if (handled && mPreparedPanel != null) {
- mPreparedPanel.isHandled = true;
- }
- }
-
- if (handled) {
- return true;
- }
- }
-
- // If a panel is open, perform a shortcut on it without the
- // chorded panel key
- if ((mPreparedPanel != null) && mPreparedPanel.isOpen) {
- if (performPanelShortcut(mPreparedPanel, keyCode, event, 0)) {
- return true;
- }
- }
- }
-
- final Callback cb = getCallback();
- final boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event)
- : super.dispatchKeyEvent(event);
- if (handled) {
- return true;
- }
- 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();
- return cb != null && mFeatureId < 0 ? cb.dispatchTouchEvent(ev) : super
- .dispatchTouchEvent(ev);
- }
-
- @Override
- public boolean dispatchTrackballEvent(MotionEvent ev) {
- final Callback cb = getCallback();
- return cb != null && mFeatureId < 0 ? cb.dispatchTrackballEvent(ev) : super
- .dispatchTrackballEvent(ev);
- }
-
- public boolean superDispatchKeyEvent(KeyEvent event) {
- return super.dispatchKeyEvent(event);
- }
-
- public boolean superDispatchTouchEvent(MotionEvent event) {
- return super.dispatchTouchEvent(event);
- }
-
- public boolean superDispatchTrackballEvent(MotionEvent event) {
- return super.dispatchTrackballEvent(event);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- return onInterceptTouchEvent(event);
- }
-
- private boolean isOutOfBounds(int x, int y) {
- return x < -5 || y < -5 || x > (getWidth() + 5)
- || y > (getHeight() + 5);
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent event) {
- int action = event.getAction();
- if (mFeatureId >= 0) {
- if (action == MotionEvent.ACTION_DOWN) {
- int x = (int)event.getX();
- int y = (int)event.getY();
- if (isOutOfBounds(x, y)) {
- closePanel(mFeatureId);
- return true;
- }
- }
- }
-
- if (!SWEEP_OPEN_MENU) {
- return false;
- }
-
- if (mFeatureId >= 0) {
- if (action == MotionEvent.ACTION_DOWN) {
- Log.i(TAG, "Watchiing!");
- mWatchingForMenu = true;
- mDownY = (int) event.getY();
- return false;
- }
-
- if (!mWatchingForMenu) {
- return false;
- }
-
- int y = (int)event.getY();
- if (action == MotionEvent.ACTION_MOVE) {
- if (y > (mDownY+30)) {
- Log.i(TAG, "Closing!");
- closePanel(mFeatureId);
- mWatchingForMenu = false;
- return true;
- }
- } else if (action == MotionEvent.ACTION_UP) {
- mWatchingForMenu = false;
- }
-
- return false;
- }
-
- //Log.i(TAG, "Intercept: action=" + action + " y=" + event.getY()
- // + " (in " + getHeight() + ")");
-
- if (action == MotionEvent.ACTION_DOWN) {
- int y = (int)event.getY();
- if (y >= (getHeight()-5) && !hasChildren()) {
- Log.i(TAG, "Watchiing!");
- mWatchingForMenu = true;
- }
- return false;
- }
-
- if (!mWatchingForMenu) {
- return false;
- }
-
- int y = (int)event.getY();
- if (action == MotionEvent.ACTION_MOVE) {
- if (y < (getHeight()-30)) {
- Log.i(TAG, "Opening!");
- openPanel(FEATURE_OPTIONS_PANEL, new KeyEvent(
- KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU));
- mWatchingForMenu = false;
- return true;
- }
- } else if (action == MotionEvent.ACTION_UP) {
- mWatchingForMenu = false;
- }
-
- return false;
- }
-
- @Override
- protected boolean setFrame(int l, int t, int r, int b) {
- boolean changed = super.setFrame(l, t, r, b);
- if (changed) {
- final Rect drawingBounds = mDrawingBounds;
- getDrawingRect(drawingBounds);
-
- Drawable fg = getForeground();
- if (fg != null) {
- final Rect frameOffsets = mFrameOffsets;
- drawingBounds.left += frameOffsets.left;
- drawingBounds.top += frameOffsets.top;
- drawingBounds.right -= frameOffsets.right;
- drawingBounds.bottom -= frameOffsets.bottom;
- fg.setBounds(drawingBounds);
- final Rect framePadding = mFramePadding;
- drawingBounds.left += framePadding.left - frameOffsets.left;
- drawingBounds.top += framePadding.top - frameOffsets.top;
- drawingBounds.right -= framePadding.right - frameOffsets.right;
- drawingBounds.bottom -= framePadding.bottom - frameOffsets.bottom;
- }
-
- Drawable bg = getBackground();
- if (bg != null) {
- bg.setBounds(drawingBounds);
- }
-
- if (SWEEP_OPEN_MENU) {
- if (mMenuBackground == null && mFeatureId < 0
- && getAttributes().height
- == WindowManager.LayoutParams.FILL_PARENT) {
- mMenuBackground = getContext().getResources().getDrawable(
- com.android.internal.R.drawable.menu_background);
- }
- if (mMenuBackground != null) {
- mMenuBackground.setBounds(drawingBounds.left,
- drawingBounds.bottom-6, drawingBounds.right,
- drawingBounds.bottom+20);
- }
- }
- }
- return changed;
- }
-
- @Override
- public void draw(Canvas canvas) {
- super.draw(canvas);
-
- if (mMenuBackground != null) {
- mMenuBackground.draw(canvas);
- }
- }
-
-
- @Override
- public boolean showContextMenuForChild(View originalView) {
- // Reuse the context menu builder
- if (mContextMenu == null) {
- mContextMenu = new ContextMenuBuilder(getContext());
- mContextMenu.setCallback(mContextMenuCallback);
- } else {
- mContextMenu.clearAll();
- }
-
- mContextMenuHelper = mContextMenu.show(originalView, originalView.getWindowToken());
- return mContextMenuHelper != null;
- }
-
- public void startChanging() {
- mChanging = true;
- }
-
- public void finishChanging() {
- mChanging = false;
- drawableChanged();
- }
-
- public void setWindowBackground(Drawable drawable) {
- if (getBackground() != drawable) {
- setBackgroundDrawable(drawable);
- if (drawable != null) {
- drawable.getPadding(mBackgroundPadding);
- } else {
- mBackgroundPadding.setEmpty();
- }
- drawableChanged();
- }
- }
-
- public void setWindowFrame(Drawable drawable) {
- if (getForeground() != drawable) {
- setForeground(drawable);
- if (drawable != null) {
- drawable.getPadding(mFramePadding);
- } else {
- mFramePadding.setEmpty();
- }
- drawableChanged();
- }
- }
-
- @Override
- protected boolean fitSystemWindows(Rect insets) {
- mFrameOffsets.set(insets);
- if (getForeground() != null) {
- drawableChanged();
- }
- return super.fitSystemWindows(insets);
- }
-
- private void drawableChanged() {
- if (mChanging) {
- return;
- }
-
- setPadding(mFramePadding.left + mBackgroundPadding.left, mFramePadding.top
- + mBackgroundPadding.top, mFramePadding.right + mBackgroundPadding.right,
- mFramePadding.bottom + mBackgroundPadding.bottom);
- requestLayout();
- invalidate();
-
- int opacity = PixelFormat.OPAQUE;
-
- // Note: if there is no background, we will assume opaque. The
- // common case seems to be that an application sets there to be
- // no background so it can draw everything itself. For that,
- // we would like to assume OPAQUE and let the app force it to
- // the slower TRANSLUCENT mode if that is really what it wants.
- Drawable bg = getBackground();
- Drawable fg = getForeground();
- if (bg != null) {
- if (fg == null) {
- opacity = bg.getOpacity();
- } else if (mFramePadding.left <= 0 && mFramePadding.top <= 0
- && mFramePadding.right <= 0 && mFramePadding.bottom <= 0) {
- // If the frame padding is zero, then we can be opaque
- // if either the frame -or- the background is opaque.
- int fop = fg.getOpacity();
- int bop = bg.getOpacity();
- if (Config.LOGV)
- Log.v(TAG, "Background opacity: " + bop + ", Frame opacity: " + fop);
- if (fop == PixelFormat.OPAQUE || bop == PixelFormat.OPAQUE) {
- opacity = PixelFormat.OPAQUE;
- } else if (fop == PixelFormat.UNKNOWN) {
- opacity = bop;
- } else if (bop == PixelFormat.UNKNOWN) {
- opacity = fop;
- } else {
- opacity = Drawable.resolveOpacity(fop, bop);
- }
- } else {
- // For now we have to assume translucent if there is a
- // frame with padding... there is no way to tell if the
- // frame and background together will draw all pixels.
- if (Config.LOGV)
- Log.v(TAG, "Padding: " + mFramePadding);
- opacity = PixelFormat.TRANSLUCENT;
- }
- }
-
- if (Config.LOGV)
- Log.v(TAG, "Background: " + bg + ", Frame: " + fg);
- if (Config.LOGV)
- Log.v(TAG, "Selected default opacity: " + opacity);
-
- mDefaultOpacity = opacity;
- if (mFeatureId < 0) {
- setDefaultWindowFormat(opacity);
- }
- }
-
- @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);
- mKeycodeMenuTimeoutHandler.removeMessages(MSG_CAMERA_LONG_PRESS);
- mKeycodeCallTimeoutActive = false;
- mKeycodeCameraTimeoutActive = false;
-
- // If the user is chording a menu shortcut, release the chord since
- // this window lost focus
- if (!hasWindowFocus && mPanelChordingKey > 0) {
- closePanel(FEATURE_OPTIONS_PANEL);
- }
-
- final Callback cb = getCallback();
- if (cb != null && mFeatureId < 0) {
- cb.onWindowFocusChanged(hasWindowFocus);
- }
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
-
- if (mFeatureId == -1) {
- /*
- * The main window has been attached, try to restore any panels
- * that may have been open before. This is called in cases where
- * an activity is being killed for configuration change and the
- * menu was open. When the activity is recreated, the menu
- * should be shown again.
- */
- openPanelsAfterRestore();
- }
- }
- }
-
- protected DecorView generateDecor() {
- return new DecorView(getContext(), -1);
- }
-
- protected void setFeatureFromAttrs(int featureId, TypedArray attrs,
- int drawableAttr, int alphaAttr) {
- Drawable d = attrs.getDrawable(drawableAttr);
- if (d != null) {
- requestFeature(featureId);
- setFeatureDefaultDrawable(featureId, d);
- }
- if ((getFeatures() & (1 << featureId)) != 0) {
- int alpha = attrs.getInt(alphaAttr, -1);
- if (alpha >= 0) {
- setFeatureDrawableAlpha(featureId, alpha);
- }
- }
- }
-
- protected ViewGroup generateLayout(DecorView decor) {
- // Apply data from current theme.
-
- TypedArray a = getWindowStyle();
-
- if (false) {
- System.out.println("From style:");
- String s = "Attrs:";
- for (int i = 0; i < com.android.internal.R.styleable.Window.length; i++) {
- s = s + " " + Integer.toHexString(com.android.internal.R.styleable.Window[i]) + "="
- + a.getString(i);
- }
- System.out.println(s);
- }
-
- mIsFloating = a.getBoolean(com.android.internal.R.styleable.Window_windowIsFloating, false);
- int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR)
- & (~getForcedWindowFlags());
- if (mIsFloating) {
- setLayout(WRAP_CONTENT, WRAP_CONTENT);
- setFlags(0, flagsToUpdate);
- } 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);
- }
-
- if (a.getBoolean(com.android.internal.R.styleable.Window_windowFullscreen, false)) {
- setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN&(~getForcedWindowFlags()));
- }
-
- 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 */
- if ((getForcedWindowFlags()&WindowManager.LayoutParams.FLAG_DIM_BEHIND) == 0) {
- params.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
- }
- params.dimAmount = a.getFloat(
- android.R.styleable.Window_backgroundDimAmount, 0.5f);
- }
-
- if (params.windowAnimations == 0) {
- 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) {
- if (mBackgroundDrawable == null) {
- if (mBackgroundResource == 0) {
- mBackgroundResource = a.getResourceId(
- com.android.internal.R.styleable.Window_windowBackground, 0);
- }
- if (mFrameResource == 0) {
- mFrameResource = a.getResourceId(com.android.internal.R.styleable.Window_windowFrame, 0);
- }
- if (false) {
- System.out.println("Background: "
- + Integer.toHexString(mBackgroundResource) + " Frame: "
- + Integer.toHexString(mFrameResource));
- }
- }
- mTextColor = a.getColor(com.android.internal.R.styleable.Window_textColor, 0xFF000000);
- }
-
- // Inflate the window decor.
-
- int layoutResource;
- int features = getLocalFeatures();
- // System.out.println("Features: 0x" + Integer.toHexString(features));
- if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
- if (mIsFloating) {
- layoutResource = com.android.internal.R.layout.dialog_title_icons;
- } else {
- layoutResource = com.android.internal.R.layout.screen_title_icons;
- }
- // System.out.println("Title Icons!");
- } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0) {
- // Special case for a window with only a progress bar (and title).
- // XXX Need to have a no-title version of embedded windows.
- layoutResource = com.android.internal.R.layout.screen_progress;
- // System.out.println("Progress!");
- } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
- // Special case for a window with a custom title.
- // If the window is floating, we need a dialog layout
- if (mIsFloating) {
- layoutResource = com.android.internal.R.layout.dialog_custom_title;
- } else {
- layoutResource = com.android.internal.R.layout.screen_custom_title;
- }
- } else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
- // If no other features and not embedded, only need a title.
- // If the window is floating, we need a dialog layout
- if (mIsFloating) {
- layoutResource = com.android.internal.R.layout.dialog_title;
- } else {
- layoutResource = com.android.internal.R.layout.screen_title;
- }
- // System.out.println("Title!");
- } else {
- // Embedded, so no decoration is needed.
- layoutResource = com.android.internal.R.layout.screen_simple;
- // System.out.println("Simple!");
- }
-
- mDecor.startChanging();
-
- View in = mLayoutInflater.inflate(layoutResource, null);
- decor.addView(in, new ViewGroup.LayoutParams(FILL_PARENT, FILL_PARENT));
-
- ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
- if (contentParent == null) {
- throw new RuntimeException("Window couldn't find content container view");
- }
-
- if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {
- ProgressBar progress = getCircularProgressBar(false);
- if (progress != null) {
- progress.setIndeterminate(true);
- }
- }
-
- // Remaining setup -- of background and title -- that only applies
- // to top-level windows.
- if (getContainer() == null) {
- Drawable drawable = mBackgroundDrawable;
- if (mBackgroundResource != 0) {
- drawable = getContext().getResources().getDrawable(mBackgroundResource);
- }
- mDecor.setWindowBackground(drawable);
- drawable = null;
- if (mFrameResource != 0) {
- drawable = getContext().getResources().getDrawable(mFrameResource);
- }
- mDecor.setWindowFrame(drawable);
-
- // System.out.println("Text=" + Integer.toHexString(mTextColor) +
- // " Sel=" + Integer.toHexString(mTextSelectedColor) +
- // " Title=" + Integer.toHexString(mTitleColor));
-
- if (mTitleColor == 0) {
- mTitleColor = mTextColor;
- }
-
- if (mTitle != null) {
- setTitle(mTitle);
- }
- setTitleColor(mTitleColor);
- }
-
- mDecor.finishChanging();
-
- return contentParent;
- }
-
- private void installDecor() {
- if (mDecor == null) {
- mDecor = generateDecor();
- mDecor.setIsRootNamespace(true);
- }
- if (mContentParent == null) {
- mContentParent = generateLayout(mDecor);
-
- mTitleView = (TextView)findViewById(com.android.internal.R.id.title);
- if (mTitleView != null) {
- if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {
- View titleContainer = findViewById(com.android.internal.R.id.title_container);
- if (titleContainer != null) {
- titleContainer.setVisibility(View.GONE);
- } else {
- mTitleView.setVisibility(View.GONE);
- }
- if (mContentParent instanceof FrameLayout) {
- ((FrameLayout)mContentParent).setForeground(null);
- }
- } else {
- mTitleView.setText(mTitle);
- }
- }
- }
- }
-
- private Drawable loadImageURI(Uri uri) {
- try {
- return Drawable.createFromStream(
- getContext().getContentResolver().openInputStream(uri), null);
- } catch (Exception e) {
- Log.w(TAG, "Unable to open content: " + uri);
- }
- return null;
- }
-
- private DrawableFeatureState getDrawableState(int featureId, boolean required) {
- if ((getFeatures() & (1 << featureId)) == 0) {
- if (!required) {
- return null;
- }
- throw new RuntimeException("The feature has not been requested");
- }
-
- DrawableFeatureState[] ar;
- if ((ar = mDrawables) == null || ar.length <= featureId) {
- DrawableFeatureState[] nar = new DrawableFeatureState[featureId + 1];
- if (ar != null) {
- System.arraycopy(ar, 0, nar, 0, ar.length);
- }
- mDrawables = ar = nar;
- }
-
- DrawableFeatureState st = ar[featureId];
- if (st == null) {
- ar[featureId] = st = new DrawableFeatureState(featureId);
- }
- return st;
- }
-
- /**
- * 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).
- * @return The panel state.
- */
- 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).
- * @param convertPanelState Optional: If the panel state does not exist, use
- * this as the panel state.
- * @return The panel state.
- */
- private PanelFeatureState getPanelState(int featureId, boolean required,
- PanelFeatureState convertPanelState) {
- if ((getFeatures() & (1 << featureId)) == 0) {
- if (!required) {
- return null;
- }
- throw new RuntimeException("The feature has not been requested");
- }
-
- PanelFeatureState[] ar;
- if ((ar = mPanels) == null || ar.length <= featureId) {
- PanelFeatureState[] nar = new PanelFeatureState[featureId + 1];
- if (ar != null) {
- System.arraycopy(ar, 0, nar, 0, ar.length);
- }
- mPanels = ar = nar;
- }
-
- PanelFeatureState st = ar[featureId];
- if (st == null) {
- ar[featureId] = st = (convertPanelState != null)
- ? convertPanelState
- : new PanelFeatureState(featureId);
- }
- return st;
- }
-
- @Override
- public final void setChildDrawable(int featureId, Drawable drawable) {
- DrawableFeatureState st = getDrawableState(featureId, true);
- st.child = drawable;
- updateDrawable(featureId, st, false);
- }
-
- @Override
- public final void setChildInt(int featureId, int value) {
- updateInt(featureId, value, false);
- }
-
- @Override
- public boolean isShortcutKey(int keyCode, KeyEvent event) {
- PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true);
- return st.menu != null && st.menu.isShortcutKey(keyCode, event);
- }
-
- private void updateDrawable(int featureId, DrawableFeatureState st, 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) {
- return;
- }
-
- final int featureMask = 1 << featureId;
-
- if ((getFeatures() & featureMask) == 0 && !fromResume) {
- return;
- }
-
- Drawable drawable = null;
- if (st != null) {
- drawable = st.child;
- if (drawable == null)
- drawable = st.local;
- if (drawable == null)
- drawable = st.def;
- }
- if ((getLocalFeatures() & featureMask) == 0) {
- if (getContainer() != null) {
- if (isActive() || fromResume) {
- getContainer().setChildDrawable(featureId, drawable);
- }
- }
- } else if (st != null && (st.cur != drawable || st.curAlpha != st.alpha)) {
- // System.out.println("Drawable changed: old=" + st.cur
- // + ", new=" + drawable);
- st.cur = drawable;
- st.curAlpha = st.alpha;
- onDrawableChanged(featureId, drawable, st.alpha);
- }
- }
-
- 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) {
- return;
- }
-
- final int featureMask = 1 << featureId;
-
- if ((getFeatures() & featureMask) == 0 && !fromResume) {
- return;
- }
-
- if ((getLocalFeatures() & featureMask) == 0) {
- if (getContainer() != null) {
- getContainer().setChildInt(featureId, value);
- }
- } else {
- onIntChanged(featureId, value);
- }
- }
-
- private ImageView getLeftIconView() {
- if (mLeftIconView != null) {
- return mLeftIconView;
- }
- if (mContentParent == null) {
- installDecor();
- }
- return (mLeftIconView = (ImageView)findViewById(com.android.internal.R.id.left_icon));
- }
-
- private ProgressBar getCircularProgressBar(boolean shouldInstallDecor) {
- if (mCircularProgressBar != null) {
- return mCircularProgressBar;
- }
- if (mContentParent == null && shouldInstallDecor) {
- installDecor();
- }
- mCircularProgressBar = (ProgressBar)findViewById(com.android.internal.R.id.progress_circular);
- mCircularProgressBar.setVisibility(View.INVISIBLE);
- return mCircularProgressBar;
- }
-
- private ProgressBar getHorizontalProgressBar(boolean shouldInstallDecor) {
- if (mHorizontalProgressBar != null) {
- return mHorizontalProgressBar;
- }
- if (mContentParent == null && shouldInstallDecor) {
- installDecor();
- }
- mHorizontalProgressBar = (ProgressBar)findViewById(com.android.internal.R.id.progress_horizontal);
- mHorizontalProgressBar.setVisibility(View.INVISIBLE);
- return mHorizontalProgressBar;
- }
-
- private ImageView getRightIconView() {
- if (mRightIconView != null) {
- return mRightIconView;
- }
- if (mContentParent == null) {
- installDecor();
- }
- return (mRightIconView = (ImageView)findViewById(com.android.internal.R.id.right_icon));
- }
-
- /**
- * Helper method for calling the {@link Callback#onPanelClosed(int, Menu)}
- * 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.
- * @param menu The menu that was closed. Optional, but give if you have.
- */
- private void callOnPanelClosed(int featureId, PanelFeatureState panel, Menu menu) {
- final Callback cb = getCallback();
- if (cb == null)
- return;
-
- // Try to get a menu
- if (menu == null) {
- // Need a panel to grab the menu, so try to get that
- if (panel == null) {
- if ((featureId >= 0) && (featureId < mPanels.length)) {
- panel = mPanels[featureId];
- }
- }
-
- if (panel != null) {
- // menu still may be null, which is okay--we tried our best
- menu = panel.menu;
- }
- }
-
- // If the panel is not open, do not callback
- if ((panel != null) && (!panel.isOpen))
- return;
-
- cb.onPanelClosed(featureId, menu);
- }
-
- /**
- * 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() {
- final Callback cb = getCallback();
- if (cb == null) {
- return false;
- } else {
- return cb.onSearchRequested();
- }
- }
-
- @Override
- public void setVolumeControlStream(int streamType) {
- mVolumeControlStreamType = streamType;
- }
-
- @Override
- public int getVolumeControlStream() {
- return mVolumeControlStreamType;
- }
-
- private static final class DrawableFeatureState {
- DrawableFeatureState(int _featureId) {
- featureId = _featureId;
- }
-
- final int featureId;
-
- int resid;
-
- Uri uri;
-
- Drawable local;
-
- Drawable child;
-
- Drawable def;
-
- Drawable cur;
-
- int alpha = 255;
-
- int curAlpha = 255;
- }
-
- private static final class PanelFeatureState {
-
- /** Feature ID for this panel. */
- int featureId;
-
- // Information pulled from the style for this panel.
-
- int background;
-
- /** The background when the panel spans the entire available width. */
- int fullBackground;
-
- int gravity;
-
- int x;
-
- int y;
-
- int windowAnimations;
-
- /** Dynamic state of the panel. */
- DecorView decorView;
-
- /** The panel that was returned by onCreatePanelView(). */
- View createdPanelView;
-
- /** The panel that we are actually showing. */
- View shownPanelView;
-
- /** Use {@link #setMenu} to set this. */
- Menu menu;
-
- /**
- * Whether the panel has been prepared (see
- * {@link PhoneWindow#preparePanel}).
- */
- boolean isPrepared;
-
- /**
- * Whether an item's action has been performed. This happens in obvious
- * scenarios (user clicks on menu item), but can also happen with
- * chording menu+(shortcut key).
- */
- boolean isHandled;
-
- boolean isOpen;
-
- /**
- * True if the menu is in expanded mode, false if the menu is in icon
- * mode
- */
- boolean isInExpandedMode;
-
- public boolean qwertyMode;
-
- boolean refreshDecorView;
-
- /**
- * Contains the state of the menu when told to freeze.
- */
- Bundle frozenMenuState;
-
- PanelFeatureState(int featureId) {
- this.featureId = featureId;
-
- refreshDecorView = false;
- }
-
- void setStyle(Context context) {
- TypedArray a = context.obtainStyledAttributes(com.android.internal.R.styleable.Theme);
- background = a.getResourceId(
- com.android.internal.R.styleable.Theme_panelBackground, 0);
- fullBackground = a.getResourceId(
- com.android.internal.R.styleable.Theme_panelFullBackground, 0);
- windowAnimations = a.getResourceId(
- com.android.internal.R.styleable.Theme_windowAnimationStyle, 0);
- a.recycle();
- }
-
- void setMenu(Menu menu) {
- this.menu = menu;
-
- if (frozenMenuState != null) {
- ((MenuBuilder) menu).restoreHierarchyState(frozenMenuState);
- frozenMenuState = null;
- }
- }
-
- Parcelable onSaveInstanceState() {
- SavedState savedState = new SavedState();
- savedState.featureId = featureId;
- savedState.isOpen = isOpen;
- savedState.isInExpandedMode = isInExpandedMode;
-
- if (menu != null) {
- savedState.menuState = new Bundle();
- ((MenuBuilder) menu).saveHierarchyState(savedState.menuState);
- }
-
- return savedState;
- }
-
- void onRestoreInstanceState(Parcelable state) {
- SavedState savedState = (SavedState) state;
- featureId = savedState.featureId;
- isOpen = savedState.isOpen;
- isInExpandedMode = savedState.isInExpandedMode;
- frozenMenuState = savedState.menuState;
-
- /*
- * A LocalActivityManager keeps the same instance of this class around.
- * The first time the menu is being shown after restoring, the
- * Activity.onCreateOptionsMenu should be called. But, if it is the
- * same instance then menu != null and we won't call that method.
- * So, clear this. Also clear any cached views.
- */
- menu = null;
- createdPanelView = null;
- shownPanelView = null;
- decorView = null;
- }
-
- private static class SavedState implements Parcelable {
- int featureId;
- boolean isOpen;
- boolean isInExpandedMode;
- Bundle menuState;
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(featureId);
- dest.writeInt(isOpen ? 1 : 0);
- dest.writeInt(isInExpandedMode ? 1 : 0);
-
- if (isOpen) {
- 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) {
- return readFromParcel(in);
- }
-
- public SavedState[] newArray(int size) {
- return new SavedState[size];
- }
- };
- }
-
- }
-
- /**
- * Simple implementation of MenuBuilder.Callback that:
- * <li> Opens a submenu when selected.
- * <li> Calls back to the callback's onMenuItemSelected when an item is
- * selected.
- */
- private final class ContextMenuCallback implements MenuBuilder.Callback {
- private int mFeatureId;
- private MenuDialogHelper mSubMenuHelper;
-
- public ContextMenuCallback(int featureId) {
- mFeatureId = featureId;
- }
-
- public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
- 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();
- mSubMenuHelper = null;
- }
- }
- }
-
- public void onCloseSubMenu(SubMenuBuilder menu) {
- Callback callback = getCallback();
- if (callback != null) callback.onPanelClosed(mFeatureId, menu.getRootMenu());
- }
-
- public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
- Callback callback = getCallback();
- return (callback != null) && callback.onMenuItemSelected(mFeatureId, item);
- }
-
- public void onMenuModeChange(MenuBuilder menu) {
- }
-
- public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
- // Set a simple callback for the submenu
- subMenu.setCallback(this);
-
- // The window manager will give us a valid window token
- mSubMenuHelper = new MenuDialogHelper(subMenu);
- mSubMenuHelper.show(null);
-
- return true;
- }
- }
-
- void sendCloseSystemWindows() {
- PhoneWindowManager.sendCloseSystemWindows(getContext(), null);
- }
-
- void sendCloseSystemWindows(String reason) {
- PhoneWindowManager.sendCloseSystemWindows(getContext(), reason);
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import android.app.Activity;
-import android.app.ActivityManagerNative;
-import android.app.IActivityManager;
-import android.app.IStatusBar;
-import android.content.BroadcastReceiver;
-import android.content.ContentQueryMap;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.database.ContentObserver;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.LocalPowerManager;
-import android.os.PowerManager;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.os.Vibrator;
-import android.provider.Settings;
-
-import com.android.internal.policy.PolicyManager;
-import com.android.internal.telephony.ITelephony;
-import android.util.Config;
-import android.util.EventLog;
-import android.util.Log;
-import android.view.Gravity;
-import android.view.HapticFeedbackConstants;
-import android.view.IWindowManager;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.WindowOrientationListener;
-import android.view.RawInputEvent;
-import android.view.Surface;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.Window;
-import android.view.WindowManager;
-import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
-import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
-import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
-import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD;
-import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_PHONE;
-import static android.view.WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
-import static android.view.WindowManager.LayoutParams.TYPE_SEARCH_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
-import android.view.WindowManagerImpl;
-import android.view.WindowManagerPolicy;
-import android.view.WindowManagerPolicy.WindowState;
-import android.media.IAudioService;
-import android.media.AudioManager;
-
-/**
- * WindowManagerPolicy implementation for the Android phone UI.
- */
-public class PhoneWindowManager implements WindowManagerPolicy {
- static final String TAG = "WindowManager";
- static final boolean DEBUG = false;
- static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
- static final boolean SHOW_STARTING_ANIMATIONS = true;
- static final boolean SHOW_PROCESSES_ON_ALT_MENU = false;
-
- static final int APPLICATION_LAYER = 1;
- static final int PHONE_LAYER = 2;
- static final int SEARCH_BAR_LAYER = 3;
- static final int STATUS_BAR_PANEL_LAYER = 4;
- // toasts and the plugged-in battery thing
- static final int TOAST_LAYER = 5;
- static final int STATUS_BAR_LAYER = 6;
- // SIM errors and unlock. Not sure if this really should be in a high layer.
- static final int PRIORITY_PHONE_LAYER = 7;
- // like the ANR / app crashed dialogs
- static final int SYSTEM_ALERT_LAYER = 8;
- // system-level error dialogs
- static final int SYSTEM_ERROR_LAYER = 9;
- // on-screen keyboards and other such input method user interfaces go here.
- static final int INPUT_METHOD_LAYER = 10;
- // on-screen keyboards and other such input method user interfaces go here.
- static final int INPUT_METHOD_DIALOG_LAYER = 11;
- // the keyguard; nothing on top of these can take focus, since they are
- // responsible for power management when displayed.
- static final int KEYGUARD_LAYER = 12;
- static final int KEYGUARD_DIALOG_LAYER = 13;
- // things in here CAN NOT take focus, but are shown on top of everything else.
- static final int SYSTEM_OVERLAY_LAYER = 14;
-
- static final int APPLICATION_PANEL_SUBLAYER = 1;
- static final int APPLICATION_MEDIA_SUBLAYER = -1;
- static final int APPLICATION_SUB_PANEL_SUBLAYER = 2;
-
- static final float SLIDE_TOUCH_EVENT_SIZE_LIMIT = 0.6f;
-
- // Debugging: set this to have the system act like there is no hard keyboard.
- static final boolean KEYBOARD_ALWAYS_HIDDEN = false;
-
- static public final String SYSTEM_DIALOG_REASON_KEY = "reason";
- static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions";
- static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
-
- // Vibrator pattern for haptic feedback of a long press.
- private static final long[] LONG_PRESS_VIBE_PATTERN = {0, 1, 40, 41};
- // Vibrator pattern for haptic feedback of a zoom ring tick
- private static final long[] ZOOM_RING_TICK_VIBE_PATTERN = {0, 10};
-
- Context mContext;
- IWindowManager mWindowManager;
- LocalPowerManager mPowerManager;
- Vibrator mVibrator; // Vibrator for giving feedback of orientation changes
-
- /** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */
- boolean mEnableShiftMenuBugReports = false;
-
- boolean mSafeMode;
- WindowState mStatusBar = null;
- WindowState mSearchBar = null;
- WindowState mKeyguard = null;
- KeyguardViewMediator mKeyguardMediator;
- GlobalActions mGlobalActions;
- boolean mShouldTurnOffOnKeyUp;
- RecentApplicationsDialog mRecentAppsDialog;
- Handler mHandler;
-
- boolean mLidOpen;
- int mSensorRotation = -1;
- boolean mScreenOn = false;
- boolean mOrientationSensorEnabled = false;
- int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
- static final int DEFAULT_ACCELEROMETER_ROTATION = 0;
- int mAccelerometerDefault = DEFAULT_ACCELEROMETER_ROTATION;
- boolean mHasSoftInput = false;
-
- // The current size of the screen.
- int mW, mH;
- // During layout, the current screen borders with all outer decoration
- // (status bar, input method dock) accounted for.
- int mCurLeft, mCurTop, mCurRight, mCurBottom;
- // During layout, the frame in which content should be displayed
- // to the user, accounting for all screen decoration except for any
- // space they deem as available for other content. This is usually
- // the same as mCur*, but may be larger if the screen decor has supplied
- // content insets.
- int mContentLeft, mContentTop, mContentRight, mContentBottom;
- // During layout, the current screen borders along with input method
- // windows are placed.
- int mDockLeft, mDockTop, mDockRight, mDockBottom;
- // During layout, the layer at which the doc window is placed.
- int mDockLayer;
-
- static final Rect mTmpParentFrame = new Rect();
- static final Rect mTmpDisplayFrame = new Rect();
- static final Rect mTmpContentFrame = new Rect();
- static final Rect mTmpVisibleFrame = new Rect();
-
- WindowState mTopFullscreenOpaqueWindowState;
- boolean mForceStatusBar;
- boolean mHomePressed;
- Intent mHomeIntent;
- boolean mSearchKeyPressed;
- boolean mConsumeSearchKeyUp;
-
- static final int ENDCALL_HOME = 0x1;
- static final int ENDCALL_SLEEPS = 0x2;
- static final int DEFAULT_ENDCALL_BEHAVIOR = ENDCALL_SLEEPS;
- int mEndcallBehavior;
-
- ShortcutManager mShortcutManager;
- PowerManager.WakeLock mBroadcastWakeLock;
-
- class SettingsObserver extends ContentObserver {
- private ContentQueryMap mSettings;
-
- SettingsObserver(Handler handler) {
- super(handler);
- }
-
- void observe() {
- ContentResolver resolver = mContext.getContentResolver();
- resolver.registerContentObserver(Settings.System.getUriFor(
- Settings.System.END_BUTTON_BEHAVIOR), false, this);
- resolver.registerContentObserver(Settings.System.getUriFor(
- Settings.System.ACCELEROMETER_ROTATION), false, this);
- resolver.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.DEFAULT_INPUT_METHOD), false, this);
- update();
- }
-
- @Override public void onChange(boolean selfChange) {
- update();
- try {
- mWindowManager.setRotation(USE_LAST_ROTATION, false);
- } catch (RemoteException e) {
- // Ignore
- }
- }
-
- public void update() {
- ContentResolver resolver = mContext.getContentResolver();
- mEndcallBehavior = Settings.System.getInt(resolver,
- Settings.System.END_BUTTON_BEHAVIOR, DEFAULT_ENDCALL_BEHAVIOR);
- int accelerometerDefault = Settings.System.getInt(resolver,
- Settings.System.ACCELEROMETER_ROTATION, DEFAULT_ACCELEROMETER_ROTATION);
- if (mAccelerometerDefault != accelerometerDefault) {
- mAccelerometerDefault = accelerometerDefault;
- updateOrientationListener();
- }
- String imId = Settings.Secure.getString(resolver,
- Settings.Secure.DEFAULT_INPUT_METHOD);
- boolean hasSoftInput = imId != null && imId.length() > 0;
- if (mHasSoftInput != hasSoftInput) {
- mHasSoftInput = hasSoftInput;
- updateRotation();
- }
- }
- }
-
- class MyOrientationListener extends WindowOrientationListener {
- private static final int _LOWER_THRESHOLD = 30;
- private static final int _UPPER_THRESHOLD = 60;
-
- MyOrientationListener(Context context) {
- super(context);
- }
-
- @Override
- public void onOrientationChanged(int orientation) {
- // ignore orientation changes unless the value is in a range
- // When switching from portrait to landscape try to use a lower threshold limit
- // Use upper threshold limit when switching from landscape to portrait
- // this is to delay the switch as much as we can
- int rotation;
- int threshold = (mSensorRotation == Surface.ROTATION_90) ? _UPPER_THRESHOLD :
- _LOWER_THRESHOLD;
-
- if ((orientation >= 0 && orientation <= _UPPER_THRESHOLD) ||
- (orientation >= 270 - _LOWER_THRESHOLD)) {
- rotation = (orientation >= 270 - _LOWER_THRESHOLD
- && orientation <= 270 + threshold)
- ? Surface.ROTATION_90 : Surface.ROTATION_0;
- } else if (orientation == WindowOrientationListener.ORIENTATION_FLAT) {
- // return portrait
- rotation = Surface.ROTATION_0;
- } else {
- // ignore orientation value
- return;
- }
- // Send updates based on orientation value
- if (rotation != mSensorRotation) {
- if(localLOGV) Log.i(TAG, "onOrientationChanged, rotation changed from "+rotation+" to "+mSensorRotation);
- // Update window manager. The lid rotation hasn't changed,
- // but we want it to re-evaluate the final rotation in case
- // it needs to call back and get the sensor orientation.
- mSensorRotation = rotation;
- try {
- mWindowManager.setRotation(rotation, false);
- } catch (RemoteException e) {
- // Ignore
- }
- }
- }
- }
- MyOrientationListener mOrientationListener;
-
- boolean useSensorForOrientation() {
- if(mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) {
- return true;
- }
- if (mAccelerometerDefault != 0 && (
- mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_USER ||
- mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) {
- return true;
- }
- return false;
- }
-
- boolean needSensorRunning() {
- if(mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) {
- // If the application has explicitly requested to follow the
- // orientation, then we need to turn the sensor or.
- return true;
- }
- if (mAccelerometerDefault != 0) {
- // If the setting for using the sensor by default is enabled, then
- // we will always leave it on. Note that the user could go to
- // a window that forces an orientation that does not use the
- // sensor and in theory we could turn it off... however, when next
- // turning it on we won't have a good value for the current
- // orientation for a little bit, which can cause orientation
- // changes to lag, so we'd like to keep it always on. (It will
- // still be turned off when the screen is off.)
- return true;
- }
- return false;
- }
-
- /*
- * Various use cases for invoking this function
- * screen turning off, should always disable listeners if already enabled
- * screen turned on and current app has sensor based orientation, enable listeners
- * if not already enabled
- * screen turned on and current app does not have sensor orientation, disable listeners if
- * already enabled
- * screen turning on and current app has sensor based orientation, enable listeners if needed
- * screen turning on and current app has nosensor based orientation, do nothing
- */
- void updateOrientationListener() {
- if (!mOrientationListener.canDetectOrientation()) {
- // If sensor is turned off or nonexistent for some reason
- return;
- }
- //Could have been invoked due to screen turning on or off or
- //change of the currently visible window's orientation
- if(localLOGV) Log.i(TAG, "Screen status="+mScreenOn+
- ", current orientation="+mCurrentAppOrientation+
- ", SensorEnabled="+mOrientationSensorEnabled);
- boolean disable = true;
- if(mScreenOn) {
- if(needSensorRunning()) {
- disable = false;
- //enable listener if not already enabled
- if(!mOrientationSensorEnabled) {
- mOrientationListener.enable();
- if(localLOGV) Log.i(TAG, "Enabling listeners");
- // We haven't had the sensor on, so don't yet know
- // the rotation.
- mSensorRotation = -1;
- mOrientationSensorEnabled = true;
- }
- }
- }
- //check if sensors need to be disabled
- if(disable && mOrientationSensorEnabled) {
- mOrientationListener.disable();
- if(localLOGV) Log.i(TAG, "Disabling listeners");
- mSensorRotation = -1;
- mOrientationSensorEnabled = false;
- }
- }
-
- Runnable mEndCallLongPress = new Runnable() {
- public void run() {
- mShouldTurnOffOnKeyUp = false;
- performHapticFeedback(null, HapticFeedbackConstants.LONG_PRESS, false);
- sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
- showGlobalActionsDialog();
- }
- };
-
- void showGlobalActionsDialog() {
- if (mGlobalActions == null) {
- mGlobalActions = new GlobalActions(mContext, mPowerManager);
- }
- final boolean keyguardShowing = mKeyguardMediator.isShowing();
- 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.pokeWakelock();
- }
- }
-
- boolean isDeviceProvisioned() {
- return Settings.Secure.getInt(
- mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0;
- }
-
- /**
- * When a home-key longpress expires, close other system windows and launch the recent apps
- */
- Runnable mHomeLongPress = new Runnable() {
- public void run() {
- /*
- * Eat the longpress so it won't dismiss the recent apps dialog when
- * the user lets go of the home key
- */
- mHomePressed = false;
- performHapticFeedback(null, HapticFeedbackConstants.LONG_PRESS, false);
- sendCloseSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS);
- showRecentAppsDialog();
- }
- };
-
- /**
- * Create (if necessary) and launch the recent apps dialog
- */
- void showRecentAppsDialog() {
- if (mRecentAppsDialog == null) {
- mRecentAppsDialog = new RecentApplicationsDialog(mContext);
- }
- mRecentAppsDialog.show();
- }
-
- /** {@inheritDoc} */
- public void init(Context context, IWindowManager windowManager,
- LocalPowerManager powerManager) {
- mContext = context;
- mWindowManager = windowManager;
- mPowerManager = powerManager;
- mKeyguardMediator = new KeyguardViewMediator(context, this, powerManager);
- mHandler = new Handler();
- mOrientationListener = new MyOrientationListener(mContext);
- SettingsObserver settingsObserver = new SettingsObserver(mHandler);
- settingsObserver.observe();
- mShortcutManager = new ShortcutManager(context, mHandler);
- mShortcutManager.observe();
- mHomeIntent = new Intent(Intent.ACTION_MAIN, null);
- mHomeIntent.addCategory(Intent.CATEGORY_HOME);
- mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
- mBroadcastWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
- "PhoneWindowManager.mBroadcastWakeLock");
- mEnableShiftMenuBugReports = "1".equals(SystemProperties.get("ro.debuggable"));
- }
-
- /** {@inheritDoc} */
- public int checkAddPermission(WindowManager.LayoutParams attrs) {
- int type = attrs.type;
- if (type < WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW
- || type > WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) {
- return WindowManagerImpl.ADD_OKAY;
- }
- String permission = null;
- switch (type) {
- case TYPE_TOAST:
- // XXX right now the app process has complete control over
- // this... should introduce a token to let the system
- // monitor/control what they are doing.
- break;
- case TYPE_INPUT_METHOD:
- // The window manager will check this.
- break;
- case TYPE_PHONE:
- case TYPE_PRIORITY_PHONE:
- case TYPE_SYSTEM_ALERT:
- case TYPE_SYSTEM_ERROR:
- case TYPE_SYSTEM_OVERLAY:
- permission = android.Manifest.permission.SYSTEM_ALERT_WINDOW;
- break;
- default:
- permission = android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
- }
- if (permission != null) {
- if (mContext.checkCallingOrSelfPermission(permission)
- != PackageManager.PERMISSION_GRANTED) {
- return WindowManagerImpl.ADD_PERMISSION_DENIED;
- }
- }
- return WindowManagerImpl.ADD_OKAY;
- }
-
- public void adjustWindowParamsLw(WindowManager.LayoutParams attrs) {
- switch (attrs.type) {
- case TYPE_SYSTEM_OVERLAY:
- case TYPE_TOAST:
- // These types of windows can't receive input events.
- attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
- break;
- }
- }
-
- void readLidState() {
- try {
- int sw = mWindowManager.getSwitchState(0);
- if (sw >= 0) {
- mLidOpen = sw == 0;
- }
- } catch (RemoteException e) {
- // Ignore
- }
- }
-
- /** {@inheritDoc} */
- public void adjustConfigurationLw(Configuration config) {
- readLidState();
- final boolean lidOpen = !KEYBOARD_ALWAYS_HIDDEN && mLidOpen;
- mPowerManager.setKeyboardVisibility(lidOpen);
- config.keyboardHidden = (lidOpen || mHasSoftInput)
- ? Configuration.KEYBOARDHIDDEN_NO
- : Configuration.KEYBOARDHIDDEN_YES;
- config.hardKeyboardHidden = lidOpen
- ? Configuration.KEYBOARDHIDDEN_NO
- : Configuration.KEYBOARDHIDDEN_YES;
- }
-
- public boolean isCheekPressedAgainstScreen(MotionEvent ev) {
- if(ev.getSize() > SLIDE_TOUCH_EVENT_SIZE_LIMIT) {
- return true;
- }
- int size = ev.getHistorySize();
- for(int i = 0; i < size; i++) {
- if(ev.getHistoricalSize(i) > SLIDE_TOUCH_EVENT_SIZE_LIMIT) {
- return true;
- }
- }
- return false;
- }
-
- /** {@inheritDoc} */
- public int windowTypeToLayerLw(int type) {
- if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
- return APPLICATION_LAYER;
- }
- switch (type) {
- case TYPE_STATUS_BAR:
- return STATUS_BAR_LAYER;
- case TYPE_STATUS_BAR_PANEL:
- return STATUS_BAR_PANEL_LAYER;
- case TYPE_SEARCH_BAR:
- return SEARCH_BAR_LAYER;
- case TYPE_PHONE:
- return PHONE_LAYER;
- case TYPE_KEYGUARD:
- return KEYGUARD_LAYER;
- case TYPE_KEYGUARD_DIALOG:
- return KEYGUARD_DIALOG_LAYER;
- case TYPE_SYSTEM_ALERT:
- return SYSTEM_ALERT_LAYER;
- case TYPE_SYSTEM_ERROR:
- return SYSTEM_ERROR_LAYER;
- case TYPE_INPUT_METHOD:
- return INPUT_METHOD_LAYER;
- case TYPE_INPUT_METHOD_DIALOG:
- return INPUT_METHOD_DIALOG_LAYER;
- case TYPE_SYSTEM_OVERLAY:
- return SYSTEM_OVERLAY_LAYER;
- case TYPE_PRIORITY_PHONE:
- return PRIORITY_PHONE_LAYER;
- case TYPE_TOAST:
- return TOAST_LAYER;
- }
- Log.e(TAG, "Unknown window type: " + type);
- return APPLICATION_LAYER;
- }
-
- /** {@inheritDoc} */
- public int subWindowTypeToLayerLw(int type) {
- switch (type) {
- case TYPE_APPLICATION_PANEL:
- case TYPE_APPLICATION_ATTACHED_DIALOG:
- return APPLICATION_PANEL_SUBLAYER;
- case TYPE_APPLICATION_MEDIA:
- return APPLICATION_MEDIA_SUBLAYER;
- case TYPE_APPLICATION_SUB_PANEL:
- return APPLICATION_SUB_PANEL_SUBLAYER;
- }
- Log.e(TAG, "Unknown sub-window type: " + type);
- return 0;
- }
-
- /** {@inheritDoc} */
- public View addStartingWindow(IBinder appToken, String packageName,
- int theme, CharSequence nonLocalizedLabel,
- int labelRes, int icon) {
- if (!SHOW_STARTING_ANIMATIONS) {
- return null;
- }
- if (packageName == null) {
- return null;
- }
-
- Context context = mContext;
- boolean setTheme = false;
- //Log.i(TAG, "addStartingWindow " + packageName + ": nonLocalizedLabel="
- // + nonLocalizedLabel + " theme=" + Integer.toHexString(theme));
- if (theme != 0 || labelRes != 0) {
- try {
- context = context.createPackageContext(packageName, 0);
- if (theme != 0) {
- context.setTheme(theme);
- setTheme = true;
- }
- } catch (PackageManager.NameNotFoundException e) {
- // Ignore
- }
- }
- if (!setTheme) {
- context.setTheme(com.android.internal.R.style.Theme);
- }
-
- Window win = PolicyManager.makeNewWindow(context);
- if (win.getWindowStyle().getBoolean(
- com.android.internal.R.styleable.Window_windowDisablePreview, false)) {
- return null;
- }
-
- Resources r = context.getResources();
- win.setTitle(r.getText(labelRes, nonLocalizedLabel));
-
- win.setType(
- WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
- // Force the window flags: this is a fake window, so it is not really
- // touchable or focusable by the user. We also add in the ALT_FOCUSABLE_IM
- // flag because we do know that the next window will take input
- // focus, so we want to get the IME window up on top of us right away.
- win.setFlags(
- WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
- WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
- WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
- WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
-
- win.setLayout(WindowManager.LayoutParams.FILL_PARENT,
- WindowManager.LayoutParams.FILL_PARENT);
-
- final WindowManager.LayoutParams params = win.getAttributes();
- params.token = appToken;
- params.packageName = packageName;
- params.windowAnimations = win.getWindowStyle().getResourceId(
- com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
- params.setTitle("Starting " + packageName);
-
- try {
- WindowManagerImpl wm = (WindowManagerImpl)
- context.getSystemService(Context.WINDOW_SERVICE);
- View view = win.getDecorView();
-
- if (win.isFloating()) {
- // Whoops, there is no way to display an animation/preview
- // of such a thing! After all that work... let's skip it.
- // (Note that we must do this here because it is in
- // getDecorView() where the theme is evaluated... maybe
- // we should peek the floating attribute from the theme
- // earlier.)
- return null;
- }
-
- if (localLOGV) Log.v(
- TAG, "Adding starting window for " + packageName
- + " / " + appToken + ": "
- + (view.getParent() != null ? view : null));
-
- wm.addView(view, params);
-
- // Only return the view if it was successfully added to the
- // window manager... which we can tell by it having a parent.
- return view.getParent() != null ? view : null;
- } catch (WindowManagerImpl.BadTokenException e) {
- // ignore
- Log.w(TAG, appToken + " already running, starting window not displayed");
- }
-
- return null;
- }
-
- /** {@inheritDoc} */
- public void removeStartingWindow(IBinder appToken, View window) {
- // RuntimeException e = new RuntimeException();
- // Log.i(TAG, "remove " + appToken + " " + window, e);
-
- if (localLOGV) Log.v(
- TAG, "Removing starting window for " + appToken + ": " + window);
-
- if (window != null) {
- WindowManagerImpl wm = (WindowManagerImpl) mContext.getSystemService(Context.WINDOW_SERVICE);
- wm.removeView(window);
- }
- }
-
- /**
- * Preflight adding a window to the system.
- *
- * Currently enforces that three window types are singletons:
- * <ul>
- * <li>STATUS_BAR_TYPE</li>
- * <li>SEARCH_BAR_TYPE</li>
- * <li>KEYGUARD_TYPE</li>
- * </ul>
- *
- * @param win The window to be added
- * @param attrs Information about the window to be added
- *
- * @return If ok, WindowManagerImpl.ADD_OKAY. If too many singletons, WindowManagerImpl.ADD_MULTIPLE_SINGLETON
- */
- public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs) {
- switch (attrs.type) {
- case TYPE_STATUS_BAR:
- if (mStatusBar != null) {
- return WindowManagerImpl.ADD_MULTIPLE_SINGLETON;
- }
- mStatusBar = win;
- break;
- case TYPE_SEARCH_BAR:
- if (mSearchBar != null) {
- return WindowManagerImpl.ADD_MULTIPLE_SINGLETON;
- }
- mSearchBar = win;
- break;
- case TYPE_KEYGUARD:
- if (mKeyguard != null) {
- return WindowManagerImpl.ADD_MULTIPLE_SINGLETON;
- }
- mKeyguard = win;
- break;
- }
- return WindowManagerImpl.ADD_OKAY;
- }
-
- /** {@inheritDoc} */
- public void removeWindowLw(WindowState win) {
- if (mStatusBar == win) {
- mStatusBar = null;
- }
- else if (mSearchBar == win) {
- mSearchBar = null;
- }
- else if (mKeyguard == win) {
- mKeyguard = null;
- }
- }
-
- static final boolean PRINT_ANIM = false;
-
- /** {@inheritDoc} */
- public int selectAnimationLw(WindowState win, int transit) {
- if (PRINT_ANIM) Log.i(TAG, "selectAnimation in " + win
- + ": transit=" + transit);
- if (transit == TRANSIT_PREVIEW_DONE) {
- if (win.hasAppShownWindows()) {
- if (PRINT_ANIM) Log.i(TAG, "**** STARTING EXIT");
- return com.android.internal.R.anim.app_starting_exit;
- }
- }
-
- return 0;
- }
-
- static ITelephony getPhoneInterface() {
- return ITelephony.Stub.asInterface(ServiceManager.checkService(Context.TELEPHONY_SERVICE));
- }
-
- static IAudioService getAudioInterface() {
- return IAudioService.Stub.asInterface(ServiceManager.checkService(Context.AUDIO_SERVICE));
- }
-
- boolean keyguardOn() {
- return keyguardIsShowingTq() || inKeyguardRestrictedKeyInputMode();
- }
-
- private static final int[] WINDOW_TYPES_WHERE_HOME_DOESNT_WORK = {
- WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
- WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
- };
-
- /** {@inheritDoc} */
- public boolean interceptKeyTi(WindowState win, int code, int metaKeys, boolean down,
- int repeatCount) {
- boolean keyguardOn = keyguardOn();
-
- if (false) {
- Log.d(TAG, "interceptKeyTi code=" + code + " down=" + down + " repeatCount="
- + repeatCount + " keyguardOn=" + keyguardOn + " mHomePressed=" + mHomePressed);
- }
-
- // Clear a pending HOME longpress if the user releases Home
- // TODO: This could probably be inside the next bit of logic, but that code
- // turned out to be a bit fragile so I'm doing it here explicitly, for now.
- if ((code == KeyEvent.KEYCODE_HOME) && !down) {
- mHandler.removeCallbacks(mHomeLongPress);
- }
-
- // If the HOME button is currently being held, then we do special
- // chording with it.
- if (mHomePressed) {
-
- // If we have released the home key, and didn't do anything else
- // while it was pressed, then it is time to go home!
- if (code == KeyEvent.KEYCODE_HOME) {
- if (!down) {
- mHomePressed = false;
-
- // If an incoming call is ringing, HOME is totally disabled.
- // (The user is already on the InCallScreen at this point,
- // and his ONLY options are to answer or reject the call.)
- boolean incomingRinging = false;
- try {
- ITelephony phoneServ = getPhoneInterface();
- if (phoneServ != null) {
- incomingRinging = phoneServ.isRinging();
- } else {
- Log.w(TAG, "Unable to find ITelephony interface");
- }
- } catch (RemoteException ex) {
- Log.w(TAG, "RemoteException from getPhoneInterface()", ex);
- }
-
- if (incomingRinging) {
- Log.i(TAG, "Ignoring HOME; there's a ringing incoming call.");
- } else {
- launchHomeFromHotKey();
- }
- }
- }
-
- return true;
- }
-
- // First we always handle the home key here, so applications
- // can never break it, although if keyguard is on, we do let
- // it handle it, because that gives us the correct 5 second
- // timeout.
- if (code == KeyEvent.KEYCODE_HOME) {
-
- // If a system window has focus, then it doesn't make sense
- // right now to interact with applications.
- WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null;
- if (attrs != null) {
- final int type = attrs.type;
- if (type == WindowManager.LayoutParams.TYPE_KEYGUARD
- || type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG) {
- // the "app" is keyguard, so give it the key
- return false;
- }
- final int typeCount = WINDOW_TYPES_WHERE_HOME_DOESNT_WORK.length;
- for (int i=0; i<typeCount; i++) {
- if (type == WINDOW_TYPES_WHERE_HOME_DOESNT_WORK[i]) {
- // don't do anything, but also don't pass it to the app
- return true;
- }
- }
- }
-
- if (down && repeatCount == 0) {
- if (!keyguardOn) {
- mHandler.postDelayed(mHomeLongPress, ViewConfiguration.getGlobalActionKeyTimeout());
- }
- mHomePressed = true;
- }
- return true;
- } else if (code == KeyEvent.KEYCODE_MENU) {
- // Hijack modified menu keys for debugging features
- final int chordBug = KeyEvent.META_SHIFT_ON;
-
- if (down && repeatCount == 0) {
- if (mEnableShiftMenuBugReports && (metaKeys & chordBug) == chordBug) {
- Intent intent = new Intent(Intent.ACTION_BUG_REPORT);
- mContext.sendOrderedBroadcast(intent, null);
- return true;
- } else if (SHOW_PROCESSES_ON_ALT_MENU &&
- (metaKeys & KeyEvent.META_ALT_ON) == KeyEvent.META_ALT_ON) {
- Intent service = new Intent();
- service.setClassName(mContext, "com.android.server.LoadAverageService");
- ContentResolver res = mContext.getContentResolver();
- boolean shown = Settings.System.getInt(
- res, Settings.System.SHOW_PROCESSES, 0) != 0;
- if (!shown) {
- mContext.startService(service);
- } else {
- mContext.stopService(service);
- }
- Settings.System.putInt(
- res, Settings.System.SHOW_PROCESSES, shown ? 0 : 1);
- return true;
- }
- }
- } else if (code == KeyEvent.KEYCODE_NOTIFICATION) {
- if (down) {
- // this key doesn't exist on current hardware, but if a device
- // didn't have a touchscreen, it would want one of these to open
- // the status bar.
- IStatusBar sbs = IStatusBar.Stub.asInterface(ServiceManager.getService("statusbar"));
- if (sbs != null) {
- try {
- sbs.toggle();
- } catch (RemoteException e) {
- // we're screwed anyway, since it's in this process
- throw new RuntimeException(e);
- }
- }
- }
- return true;
- } else if (code == KeyEvent.KEYCODE_SEARCH) {
- if (down) {
- if (repeatCount == 0) {
- mSearchKeyPressed = true;
- }
- } else {
- mSearchKeyPressed = false;
-
- if (mConsumeSearchKeyUp) {
- // Consume the up-event
- mConsumeSearchKeyUp = false;
- return true;
- }
- }
- }
-
- // Shortcuts are invoked through Search+key, so intercept those here
- if (mSearchKeyPressed) {
- if (down && repeatCount == 0 && !keyguardOn) {
- Intent shortcutIntent = mShortcutManager.getIntent(code, metaKeys);
- if (shortcutIntent != null) {
- shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- mContext.startActivity(shortcutIntent);
-
- /*
- * We launched an app, so the up-event of the search key
- * should be consumed
- */
- mConsumeSearchKeyUp = true;
- return true;
- }
- }
- }
-
- return false;
- }
-
- /**
- * A home key -> launch home action was detected. Take the appropriate action
- * given the situation with the keyguard.
- */
- void launchHomeFromHotKey() {
- if (mKeyguardMediator.isShowing()) {
- // don't launch home if keyguard showing
- } else if (mKeyguardMediator.isInputRestricted()) {
- // when in keyguard restricted mode, must first verify unlock
- // before launching home
- mKeyguardMediator.verifyUnlock(new OnKeyguardExitResult() {
- public void onKeyguardExitResult(boolean success) {
- if (success) {
- mContext.startActivity(mHomeIntent);
- sendCloseSystemWindows();
- }
- }
- });
- } else {
- // no keyguard stuff to worry about, just launch home!
- mContext.startActivity(mHomeIntent);
- sendCloseSystemWindows();
- }
- }
-
- public void getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect contentInset) {
- final int fl = attrs.flags;
-
- if ((fl &
- (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR))
- == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
- contentInset.set(mCurLeft, mCurTop, mW - mCurRight, mH - mCurBottom);
- } else {
- contentInset.setEmpty();
- }
- }
-
- /** {@inheritDoc} */
- public void beginLayoutLw(int displayWidth, int displayHeight) {
- mW = displayWidth;
- mH = displayHeight;
- mDockLeft = mContentLeft = mCurLeft = 0;
- mDockTop = mContentTop = mCurTop = 0;
- mDockRight = mContentRight = mCurRight = displayWidth;
- mDockBottom = mContentBottom = mCurBottom = displayHeight;
- mDockLayer = 0x10000000;
-
- // decide where the status bar goes ahead of time
- if (mStatusBar != null) {
- final Rect pf = mTmpParentFrame;
- final Rect df = mTmpDisplayFrame;
- final Rect vf = mTmpVisibleFrame;
- pf.left = df.left = vf.left = 0;
- pf.top = df.top = vf.top = 0;
- pf.right = df.right = vf.right = displayWidth;
- pf.bottom = df.bottom = vf.bottom = displayHeight;
-
- mStatusBar.computeFrameLw(pf, df, vf, vf);
- if (mStatusBar.isVisibleLw()) {
- // If the status bar is hidden, we don't want to cause
- // windows behind it to scroll.
- mDockTop = mContentTop = mCurTop = mStatusBar.getFrameLw().bottom;
- }
- }
- }
-
- void setAttachedWindowFrames(WindowState win, int fl, int sim,
- WindowState attached, boolean insetDecors, Rect pf, Rect df, Rect cf, Rect vf) {
- if (win.getSurfaceLayer() > mDockLayer && attached.getSurfaceLayer() < mDockLayer) {
- // Here's a special case: if this attached window is a panel that is
- // above the dock window, and the window it is attached to is below
- // the dock window, then the frames we computed for the window it is
- // attached to can not be used because the dock is effectively part
- // of the underlying window and the attached window is floating on top
- // of the whole thing. So, we ignore the attached window and explicitly
- // compute the frames that would be appropriate without the dock.
- df.left = cf.left = vf.left = mDockLeft;
- df.top = cf.top = vf.top = mDockTop;
- df.right = cf.right = vf.right = mDockRight;
- df.bottom = cf.bottom = vf.bottom = mDockBottom;
- } else {
- // The effective display frame of the attached window depends on
- // whether it is taking care of insetting its content. If not,
- // we need to use the parent's content frame so that the entire
- // window is positioned within that content. Otherwise we can use
- // the display frame and let the attached window take care of
- // positioning its content appropriately.
- if ((sim & SOFT_INPUT_MASK_ADJUST) != SOFT_INPUT_ADJUST_RESIZE) {
- cf.set(attached.getDisplayFrameLw());
- } else {
- // If the window is resizing, then we want to base the content
- // frame on our attached content frame to resize... however,
- // things can be tricky if the attached window is NOT in resize
- // mode, in which case its content frame will be larger.
- // Ungh. So to deal with that, make sure the content frame
- // we end up using is not covering the IM dock.
- cf.set(attached.getContentFrameLw());
- if (attached.getSurfaceLayer() < mDockLayer) {
- if (cf.left < mContentLeft) cf.left = mContentLeft;
- if (cf.top < mContentTop) cf.top = mContentTop;
- if (cf.right > mContentRight) cf.right = mContentRight;
- if (cf.bottom > mContentBottom) cf.bottom = mContentBottom;
- }
- }
- df.set(insetDecors ? attached.getDisplayFrameLw() : cf);
- vf.set(attached.getVisibleFrameLw());
- }
- // The LAYOUT_IN_SCREEN flag is used to determine whether the attached
- // window should be positioned relative to its parent or the entire
- // screen.
- pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0
- ? attached.getFrameLw() : df);
- }
-
- /** {@inheritDoc} */
- public void layoutWindowLw(WindowState win, WindowManager.LayoutParams attrs, WindowState attached) {
- // we've already done the status bar
- if (win == mStatusBar) {
- return;
- }
-
- if (false) {
- if ("com.google.android.youtube".equals(attrs.packageName)
- && attrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
- Log.i(TAG, "GOTCHA!");
- }
- }
-
- final int fl = attrs.flags;
- final int sim = attrs.softInputMode;
-
- final Rect pf = mTmpParentFrame;
- final Rect df = mTmpDisplayFrame;
- final Rect cf = mTmpContentFrame;
- final Rect vf = mTmpVisibleFrame;
-
- if (attrs.type == TYPE_INPUT_METHOD) {
- pf.left = df.left = cf.left = vf.left = mDockLeft;
- pf.top = df.top = cf.top = vf.top = mDockTop;
- pf.right = df.right = cf.right = vf.right = mDockRight;
- pf.bottom = df.bottom = cf.bottom = vf.bottom = mDockBottom;
- // IM dock windows always go to the bottom of the screen.
- attrs.gravity = Gravity.BOTTOM;
- mDockLayer = win.getSurfaceLayer();
- } else {
- if ((fl &
- (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR))
- == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
- // This is the case for a normal activity window: we want it
- // to cover all of the screen space, and it can take care of
- // moving its contents to account for screen decorations that
- // intrude into that space.
- if (attached != null) {
- // If this window is attached to another, our display
- // frame is the same as the one we are attached to.
- setAttachedWindowFrames(win, fl, sim, attached, true, pf, df, cf, vf);
- } else {
- pf.left = df.left = 0;
- pf.top = df.top = 0;
- pf.right = df.right = mW;
- pf.bottom = df.bottom = mH;
- if ((sim & SOFT_INPUT_MASK_ADJUST) != SOFT_INPUT_ADJUST_RESIZE) {
- cf.left = mDockLeft;
- cf.top = mDockTop;
- cf.right = mDockRight;
- cf.bottom = mDockBottom;
- } else {
- cf.left = mContentLeft;
- cf.top = mContentTop;
- cf.right = mContentRight;
- cf.bottom = mContentBottom;
- }
- vf.left = mCurLeft;
- vf.top = mCurTop;
- vf.right = mCurRight;
- vf.bottom = mCurBottom;
- }
- } else if ((fl & FLAG_LAYOUT_IN_SCREEN) != 0) {
- // A window that has requested to fill the entire screen just
- // gets everything, period.
- pf.left = df.left = cf.left = 0;
- pf.top = df.top = cf.top = 0;
- pf.right = df.right = cf.right = mW;
- pf.bottom = df.bottom = cf.bottom = mH;
- vf.left = mCurLeft;
- vf.top = mCurTop;
- vf.right = mCurRight;
- vf.bottom = mCurBottom;
- } else if (attached != null) {
- // A child window should be placed inside of the same visible
- // frame that its parent had.
- setAttachedWindowFrames(win, fl, sim, attached, false, pf, df, cf, vf);
- } else {
- // Otherwise, a normal window must be placed inside the content
- // of all screen decorations.
- pf.left = mContentLeft;
- pf.top = mContentTop;
- pf.right = mContentRight;
- pf.bottom = mContentBottom;
- if ((sim & SOFT_INPUT_MASK_ADJUST) != SOFT_INPUT_ADJUST_RESIZE) {
- df.left = cf.left = mDockLeft;
- df.top = cf.top = mDockTop;
- df.right = cf.right = mDockRight;
- df.bottom = cf.bottom = mDockBottom;
- } else {
- df.left = cf.left = mContentLeft;
- df.top = cf.top = mContentTop;
- df.right = cf.right = mContentRight;
- df.bottom = cf.bottom = mContentBottom;
- }
- vf.left = mCurLeft;
- vf.top = mCurTop;
- vf.right = mCurRight;
- vf.bottom = mCurBottom;
- }
- }
-
- if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0) {
- df.left = df.top = cf.left = cf.top = vf.left = vf.top = -10000;
- df.right = df.bottom = cf.right = cf.bottom = vf.right = vf.bottom = 10000;
- }
-
- if (false) {
- if ("com.google.android.youtube".equals(attrs.packageName)
- && attrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
- if (true || localLOGV) Log.v(TAG, "Computing frame of " + win +
- ": pf=" + pf.toShortString() + " df=" + df.toShortString()
- + " cf=" + cf.toShortString() + " vf=" + vf.toShortString());
- }
- }
-
- win.computeFrameLw(pf, df, cf, vf);
-
- // Dock windows carve out the bottom of the screen, so normal windows
- // can't appear underneath them.
- if (attrs.type == TYPE_INPUT_METHOD && !win.getGivenInsetsPendingLw()) {
- int top = win.getContentFrameLw().top;
- top += win.getGivenContentInsetsLw().top;
- if (mContentBottom > top) {
- mContentBottom = top;
- }
- top = win.getVisibleFrameLw().top;
- top += win.getGivenVisibleInsetsLw().top;
- if (mCurBottom > top) {
- mCurBottom = top;
- }
- }
- }
-
- /** {@inheritDoc} */
- public void finishLayoutLw() {
- }
-
- /** {@inheritDoc} */
- public void beginAnimationLw(int displayWidth, int displayHeight) {
- mTopFullscreenOpaqueWindowState = null;
- mForceStatusBar = false;
- }
-
- /** {@inheritDoc} */
- public void animatingWindowLw(WindowState win,
- WindowManager.LayoutParams attrs) {
- if (win.isVisibleLw()) {
- if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
- mForceStatusBar = true;
- } else if (mTopFullscreenOpaqueWindowState == null
- && attrs.type >= FIRST_APPLICATION_WINDOW
- && attrs.type <= LAST_APPLICATION_WINDOW
- && win.fillsScreenLw(mW, mH, true, false)
- && win.isVisibleLw()) {
- mTopFullscreenOpaqueWindowState = win;
- }
- }
- }
-
- /** {@inheritDoc} */
- public boolean finishAnimationLw() {
- boolean changed = false;
- if (mStatusBar != null) {
- //Log.i(TAG, "force=" + mForceStatusBar
- // + " top=" + mTopFullscreenOpaqueWindowState);
- if (mForceStatusBar) {
- changed |= mStatusBar.showLw(true);
- } else if (mTopFullscreenOpaqueWindowState != null) {
- //Log.i(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw()
- // + " shown frame: " + mTopFullscreenOpaqueWindowState.getShownFrameLw());
- //Log.i(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs());
- WindowManager.LayoutParams lp =
- mTopFullscreenOpaqueWindowState.getAttrs();
- boolean hideStatusBar =
- (lp.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
- if (hideStatusBar) {
- changed |= mStatusBar.hideLw(true);
- } else {
- changed |= mStatusBar.showLw(true);
- }
- }
- }
- return changed;
- }
-
- /** {@inheritDoc} */
- public boolean preprocessInputEventTq(RawInputEvent event) {
- switch (event.type) {
- case RawInputEvent.EV_SW:
- if (event.keycode == 0) {
- // lid changed state
- mLidOpen = event.value == 0;
- updateRotation();
- if (keyguardIsShowingTq()) {
- if (mLidOpen) {
- // only do this if it's opening -- closing the device shouldn't turn it
- // off, but it also shouldn't turn it on.
- mKeyguardMediator.pokeWakelock();
- }
- } else {
- // Light up the keyboard if we are sliding up.
- if (mLidOpen) {
- mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
- LocalPowerManager.BUTTON_EVENT);
- } else {
- mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
- LocalPowerManager.OTHER_EVENT);
- }
- }
- }
- }
- return false;
- }
-
-
- /** {@inheritDoc} */
- public boolean isAppSwitchKeyTqTiLwLi(int keycode) {
- return keycode == KeyEvent.KEYCODE_HOME
- || keycode == KeyEvent.KEYCODE_ENDCALL;
- }
-
- /** {@inheritDoc} */
- public boolean isMovementKeyTi(int keycode) {
- switch (keycode) {
- case KeyEvent.KEYCODE_DPAD_UP:
- case KeyEvent.KEYCODE_DPAD_DOWN:
- case KeyEvent.KEYCODE_DPAD_LEFT:
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- return true;
- }
- return false;
- }
-
-
- /**
- * @return Whether a telephone call is in progress right now.
- */
- boolean isInCall() {
- final ITelephony phone = getPhoneInterface();
- if (phone == null) {
- Log.w(TAG, "couldn't get ITelephony reference");
- return false;
- }
- try {
- return phone.isOffhook();
- } catch (RemoteException e) {
- Log.w(TAG, "ITelephony.isOffhhook threw RemoteException " + e);
- return false;
- }
- }
-
- /**
- * @return Whether music is being played right now.
- */
- boolean isMusicActive() {
- final IAudioService audio = getAudioInterface();
- if (audio == null) {
- Log.w(TAG, "isMusicActive: couldn't get IAudioService reference");
- return false;
- }
- try {
- return audio.isMusicActive();
- } catch (RemoteException e) {
- Log.w(TAG, "IAudioService.isMusicActive() threw RemoteException " + e);
- return false;
- }
- }
-
- /**
- * Tell the audio service to adjust the volume appropriate to the event.
- * @param keycode
- */
- void sendVolToMusic(int keycode) {
- final IAudioService audio = getAudioInterface();
- if (audio == null) {
- Log.w(TAG, "sendVolToMusic: couldn't get IAudioService reference");
- return;
- }
- try {
- // since audio is playing, we shouldn't have to hold a wake lock
- // during the call, but we do it as a precaution for the rare possibility
- // that the music stops right before we call this
- mBroadcastWakeLock.acquire();
- audio.adjustStreamVolume(
- AudioManager.STREAM_MUSIC,
- keycode == KeyEvent.KEYCODE_VOLUME_UP
- ? AudioManager.ADJUST_RAISE
- : AudioManager.ADJUST_LOWER,
- 0);
- } catch (RemoteException e) {
- Log.w(TAG, "IAudioService.adjustStreamVolume() threw RemoteException " + e);
- } finally {
- mBroadcastWakeLock.release();
- }
- }
-
- static boolean isMediaKey(int code) {
- if (code == KeyEvent.KEYCODE_HEADSETHOOK ||
- code == KeyEvent.KEYCODE_PLAYPAUSE ||
- code == KeyEvent.KEYCODE_STOP ||
- code == KeyEvent.KEYCODE_NEXTSONG ||
- code == KeyEvent.KEYCODE_PREVIOUSSONG ||
- code == KeyEvent.KEYCODE_PREVIOUSSONG ||
- code == KeyEvent.KEYCODE_FORWARD) {
- return true;
- }
- return false;
- }
-
- /** {@inheritDoc} */
- public int interceptKeyTq(RawInputEvent event, boolean screenIsOn) {
- int result = ACTION_PASS_TO_USER;
- final boolean isWakeKey = isWakeKeyTq(event);
- final boolean keyguardShowing = keyguardIsShowingTq();
-
- if (false) {
- Log.d(TAG, "interceptKeyTq event=" + event + " keycode=" + event.keycode
- + " screenIsOn=" + screenIsOn + " keyguardShowing=" + keyguardShowing);
- }
-
- if (keyguardShowing) {
- if (screenIsOn) {
- // when the screen is on, always give the event to the keyguard
- result |= ACTION_PASS_TO_USER;
- } else {
- // otherwise, don't pass it to the user
- result &= ~ACTION_PASS_TO_USER;
-
- final boolean isKeyDown =
- (event.type == RawInputEvent.EV_KEY) && (event.value != 0);
- if (isWakeKey && isKeyDown) {
-
- // tell the mediator about a wake key, it may decide to
- // turn on the screen depending on whether the key is
- // appropriate.
- if (!mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(event.keycode)
- && (event.keycode == KeyEvent.KEYCODE_VOLUME_DOWN
- || event.keycode == KeyEvent.KEYCODE_VOLUME_UP)) {
- if (isInCall()) {
- // if the keyguard didn't wake the device, we are in call, and
- // it is a volume key, turn on the screen so that the user
- // can more easily adjust the in call volume.
- mKeyguardMediator.pokeWakelock();
- } else if (isMusicActive()) {
- // when keyguard is showing and screen off, we need
- // to handle the volume key for music here
- sendVolToMusic(event.keycode);
- }
- }
- }
- }
- } else if (!screenIsOn) {
- if (isWakeKey) {
- // a wake key has a sole purpose of waking the device; don't pass
- // it to the user
- result |= ACTION_POKE_USER_ACTIVITY;
- result &= ~ACTION_PASS_TO_USER;
- }
- }
-
- int type = event.type;
- int code = event.keycode;
- boolean down = event.value != 0;
-
- if (type == RawInputEvent.EV_KEY) {
- if (code == KeyEvent.KEYCODE_ENDCALL) {
- if (down) {
- boolean hungUp = false;
- // key repeats are generated by the window manager, and we don't see them
- // here, so unless the driver is doing something it shouldn't be, we know
- // this is the real press event.
- try {
- ITelephony phoneServ = getPhoneInterface();
- if (phoneServ != null) {
- hungUp = phoneServ.endCall();
- } else {
- Log.w(TAG, "!!! Unable to find ITelephony interface !!!");
- }
- } catch (RemoteException ex) {
- Log.w(TAG, "ITelephony.endCall() threw RemoteException" + ex);
- }
- if (hungUp || !screenIsOn) {
- mShouldTurnOffOnKeyUp = false;
- } else {
- // only try to turn off the screen if we didn't already hang up
- mShouldTurnOffOnKeyUp = true;
- mHandler.postDelayed(mEndCallLongPress,
- ViewConfiguration.getGlobalActionKeyTimeout());
- result &= ~ACTION_PASS_TO_USER;
- }
- } else {
- mHandler.removeCallbacks(mEndCallLongPress);
- if (mShouldTurnOffOnKeyUp) {
- mShouldTurnOffOnKeyUp = false;
- boolean gohome = (mEndcallBehavior & ENDCALL_HOME) != 0;
- boolean sleeps = (mEndcallBehavior & ENDCALL_SLEEPS) != 0;
- if (keyguardShowing
- || (sleeps && !gohome)
- || (gohome && !goHome() && sleeps)) {
- // they must already be on the keyguad or home screen,
- // go to sleep instead
- Log.d(TAG, "I'm tired mEndcallBehavior=0x"
- + Integer.toHexString(mEndcallBehavior));
- result &= ~ACTION_POKE_USER_ACTIVITY;
- result |= ACTION_GO_TO_SLEEP;
- }
- result &= ~ACTION_PASS_TO_USER;
- }
- }
- } else if (isMediaKey(code)) {
- // This key needs to be handled even if the screen is off.
- // If others need to be handled while it's off, this is a reasonable
- // pattern to follow.
- if ((result & ACTION_PASS_TO_USER) == 0) {
- // Only do this if we would otherwise not pass it to the user. In that
- // case, the PhoneWindow class will do the same thing, except it will
- // only do it if the showing app doesn't process the key on its own.
- KeyEvent keyEvent = new KeyEvent(event.when, event.when,
- down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP,
- code, 0);
- mBroadcastWakeLock.acquire();
- mHandler.post(new PassHeadsetKey(keyEvent));
- }
- } else if (code == KeyEvent.KEYCODE_CALL) {
- // If an incoming call is ringing, answer it!
- // (We handle this key here, rather than in the InCallScreen, to make
- // sure we'll respond to the key even if the InCallScreen hasn't come to
- // the foreground yet.)
-
- // We answer the call on the DOWN event, to agree with
- // the "fallback" behavior in the InCallScreen.
- if (down) {
- try {
- ITelephony phoneServ = getPhoneInterface();
- if (phoneServ != null) {
- if (phoneServ.isRinging()) {
- Log.i(TAG, "interceptKeyTq:"
- + " CALL key-down while ringing: Answer the call!");
- phoneServ.answerRingingCall();
-
- // And *don't* pass this key thru to the current activity
- // (which is presumably the InCallScreen.)
- result &= ~ACTION_PASS_TO_USER;
- }
- } else {
- Log.w(TAG, "CALL button: Unable to find ITelephony interface");
- }
- } catch (RemoteException ex) {
- Log.w(TAG, "CALL button: RemoteException from getPhoneInterface()", ex);
- }
- }
- } else if ((code == KeyEvent.KEYCODE_VOLUME_UP)
- || (code == KeyEvent.KEYCODE_VOLUME_DOWN)) {
- // If an incoming call is ringing, either VOLUME key means
- // "silence ringer". We handle these keys here, rather than
- // in the InCallScreen, to make sure we'll respond to them
- // even if the InCallScreen hasn't come to the foreground yet.
-
- // Look for the DOWN event here, to agree with the "fallback"
- // behavior in the InCallScreen.
- if (down) {
- try {
- ITelephony phoneServ = getPhoneInterface();
- if (phoneServ != null) {
- if (phoneServ.isRinging()) {
- Log.i(TAG, "interceptKeyTq:"
- + " VOLUME key-down while ringing: Silence ringer!");
- // Silence the ringer. (It's safe to call this
- // even if the ringer has already been silenced.)
- phoneServ.silenceRinger();
-
- // And *don't* pass this key thru to the current activity
- // (which is probably the InCallScreen.)
- result &= ~ACTION_PASS_TO_USER;
- }
- } else {
- Log.w(TAG, "VOLUME button: Unable to find ITelephony interface");
- }
- } catch (RemoteException ex) {
- Log.w(TAG, "VOLUME button: RemoteException from getPhoneInterface()", ex);
- }
- }
- }
- }
-
- return result;
- }
-
- class PassHeadsetKey implements Runnable {
- KeyEvent mKeyEvent;
-
- PassHeadsetKey(KeyEvent keyEvent) {
- mKeyEvent = keyEvent;
- }
-
- public void run() {
- if (ActivityManagerNative.isSystemReady()) {
- Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
- intent.putExtra(Intent.EXTRA_KEY_EVENT, mKeyEvent);
- mContext.sendOrderedBroadcast(intent, null, mBroadcastDone,
- mHandler, Activity.RESULT_OK, null, null);
- }
- }
- }
-
- BroadcastReceiver mBroadcastDone = new BroadcastReceiver() {
- public void onReceive(Context context, Intent intent) {
- mBroadcastWakeLock.release();
- }
- };
-
- /** {@inheritDoc} */
- public boolean isWakeRelMovementTq(int device, int classes,
- RawInputEvent event) {
- // if it's tagged with one of the wake bits, it wakes up the device
- return ((event.flags & (FLAG_WAKE | FLAG_WAKE_DROPPED)) != 0);
- }
-
- /** {@inheritDoc} */
- public boolean isWakeAbsMovementTq(int device, int classes,
- RawInputEvent event) {
- // if it's tagged with one of the wake bits, it wakes up the device
- return ((event.flags & (FLAG_WAKE | FLAG_WAKE_DROPPED)) != 0);
- }
-
- /**
- * Given the current state of the world, should this key wake up the device?
- */
- protected boolean isWakeKeyTq(RawInputEvent event) {
- // There are not key maps for trackball devices, but we'd still
- // like to have pressing it wake the device up, so force it here.
- int keycode = event.keycode;
- int flags = event.flags;
- if (keycode == RawInputEvent.BTN_MOUSE) {
- flags |= WindowManagerPolicy.FLAG_WAKE;
- }
- return (flags
- & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
- }
-
- /** {@inheritDoc} */
- public void screenTurnedOff(int why) {
- EventLog.writeEvent(70000, 0);
- mKeyguardMediator.onScreenTurnedOff(why);
- mScreenOn = false;
- updateOrientationListener();
- }
-
- /** {@inheritDoc} */
- public void screenTurnedOn() {
- EventLog.writeEvent(70000, 1);
- mKeyguardMediator.onScreenTurnedOn();
- mScreenOn = true;
- updateOrientationListener();
- }
-
- /** {@inheritDoc} */
- public void enableKeyguard(boolean enabled) {
- mKeyguardMediator.setKeyguardEnabled(enabled);
- }
-
- /** {@inheritDoc} */
- public void exitKeyguardSecurely(OnKeyguardExitResult callback) {
- mKeyguardMediator.verifyUnlock(callback);
- }
-
- /** {@inheritDoc} */
- public boolean keyguardIsShowingTq() {
- return mKeyguardMediator.isShowing();
- }
-
- /** {@inheritDoc} */
- public boolean inKeyguardRestrictedKeyInputMode() {
- return mKeyguardMediator.isInputRestricted();
- }
-
- /**
- * Callback from {@link KeyguardViewMediator}
- */
- public void onKeyguardShow() {
- sendCloseSystemWindows();
- }
-
- void sendCloseSystemWindows() {
- sendCloseSystemWindows(mContext, null);
- }
-
- void sendCloseSystemWindows(String reason) {
- sendCloseSystemWindows(mContext, reason);
- }
-
- static void sendCloseSystemWindows(Context context, String reason) {
- if (ActivityManagerNative.isSystemReady()) {
- Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
- if (reason != null) {
- intent.putExtra(SYSTEM_DIALOG_REASON_KEY, reason);
- }
- context.sendBroadcast(intent);
- }
- }
-
- public int rotationForOrientation(int orientation, int lastRotation,
- boolean displayEnabled) {
- switch (orientation) {
- case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:
- //always return landscape if orientation set to landscape
- return Surface.ROTATION_90;
- case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
- //always return portrait if orientation set to portrait
- return Surface.ROTATION_0;
- }
- // case for nosensor meaning ignore sensor and consider only lid
- // or orientation sensor disabled
- //or case.unspecified
- if (mLidOpen) {
- return Surface.ROTATION_90;
- } else {
- if (useSensorForOrientation()) {
- // If the user has enabled auto rotation by default, do it.
- return mSensorRotation >= 0 ? mSensorRotation : lastRotation;
- }
- return Surface.ROTATION_0;
- }
- }
-
- public boolean detectSafeMode() {
- try {
- int menuState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_MENU);
- mSafeMode = menuState > 0;
- Log.i(TAG, "Menu key state: " + menuState + " safeMode=" + mSafeMode);
- return mSafeMode;
- } catch (RemoteException e) {
- // Doom! (it's also local)
- throw new RuntimeException("window manager dead");
- }
- }
-
- /** {@inheritDoc} */
- public void systemReady() {
- try {
- if (mSafeMode) {
- // If the user is holding the menu key code, then we are
- // going to boot into safe mode.
- ActivityManagerNative.getDefault().enterSafeMode();
- }
- // tell the keyguard
- mKeyguardMediator.onSystemReady();
- android.os.SystemProperties.set("dev.bootcomplete", "1");
- updateOrientationListener();
- mVibrator = new Vibrator();
- } catch (RemoteException e) {
- // Ignore
- }
- }
-
-
- /** {@inheritDoc} */
- public void enableScreenAfterBoot() {
- readLidState();
- updateRotation();
- }
-
- void updateRotation() {
- mPowerManager.setKeyboardVisibility(mLidOpen);
- int rotation= Surface.ROTATION_0;
- if (mLidOpen) {
- // always use landscape if lid is open
- rotation = Surface.ROTATION_90;
- }
- //if lid is closed orientation will be portrait
- try {
- //set orientation on WindowManager
- mWindowManager.setRotation(rotation, true);
- } catch (RemoteException e) {
- // Ignore
- }
- }
-
- /**
- * goes to the home screen
- * @return whether it did anything
- */
- boolean goHome() {
- if (false) {
- // This code always brings home to the front.
- mContext.startActivity(mHomeIntent);
- } else {
- // This code brings home to the front or, if it is already
- // at the front, puts the device to sleep.
- try {
- int result = ActivityManagerNative.getDefault()
- .startActivity(null, mHomeIntent,
- mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
- null, 0, null, null, 0, true /* onlyIfNeeded*/, false);
- if (result == IActivityManager.START_RETURN_INTENT_TO_CALLER) {
- return false;
- }
- } catch (RemoteException ex) {
- // bummer, the activity manager, which is in this process, is dead
- }
- }
- sendCloseSystemWindows();
- return true;
- }
-
- public void setCurrentOrientation(int newOrientation) {
- if(newOrientation != mCurrentAppOrientation) {
- mCurrentAppOrientation = newOrientation;
- updateOrientationListener();
- }
- }
-
- public boolean performHapticFeedback(WindowState win, int effectId, boolean always) {
- if (!always && Settings.System.getInt(mContext.getContentResolver(),
- Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) == 0) {
- return false;
- }
- switch (effectId) {
- case HapticFeedbackConstants.LONG_PRESS:
- mVibrator.vibrate(LONG_PRESS_VIBE_PATTERN, -1);
- return true;
- case HapticFeedbackConstants.ZOOM_RING_TICK:
- mVibrator.vibrate(ZOOM_RING_TICK_VIBE_PATTERN, -1);
- }
- return false;
- }
-
- public void screenOnStopped() {
- if (!mKeyguardMediator.isShowing()) {
- long curTime = SystemClock.uptimeMillis();
- mPowerManager.userActivity(curTime, false, LocalPowerManager.OTHER_EVENT);
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import android.content.Context;
-import android.util.Log;
-
-import com.android.internal.policy.IPolicy;
-import com.android.internal.policy.impl.PhoneLayoutInflater;
-import com.android.internal.policy.impl.PhoneWindow;
-import com.android.internal.policy.impl.PhoneWindowManager;
-
-/**
- * {@hide}
- */
-
-// Simple implementation of the policy interface that spawns the right
-// set of objects
-public class Policy implements IPolicy {
- private static final String TAG = "PhonePolicy";
-
- private static final String[] preload_classes = {
- "com.android.internal.policy.impl.PhoneLayoutInflater",
- "com.android.internal.policy.impl.PhoneWindow",
- "com.android.internal.policy.impl.PhoneWindow$1",
- "com.android.internal.policy.impl.PhoneWindow$ContextMenuCallback",
- "com.android.internal.policy.impl.PhoneWindow$DecorView",
- "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState",
- "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState$SavedState",
- };
-
- static {
- // For performance reasons, preload some policy specific classes when
- // the policy gets loaded.
- for (String s : preload_classes) {
- try {
- Class.forName(s);
- } catch (ClassNotFoundException ex) {
- Log.e(TAG, "Could not preload class for phone policy: " + s);
- }
- }
- }
-
- public PhoneWindow makeNewWindow(Context context) {
- return new PhoneWindow(context);
- }
-
- public PhoneLayoutInflater makeNewLayoutInflater(Context context) {
- return new PhoneLayoutInflater(context);
- }
-
- public PhoneWindowManager makeNewWindowManager() {
- return new PhoneWindowManager();
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import com.android.internal.R;
-
-import android.app.Dialog;
-import android.app.StatusBarManager;
-import android.content.Context;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.os.IServiceManager;
-import android.os.LocalPowerManager;
-import android.os.ServiceManager;
-import android.os.ServiceManagerNative;
-import android.os.SystemClock;
-import com.android.internal.telephony.ITelephony;
-import android.view.KeyEvent;
-import android.util.Log;
-import android.view.View;
-import android.view.WindowManager;
-import android.view.View.OnClickListener;
-import android.view.View.OnKeyListener;
-import android.widget.Button;
-
-/**
- * @deprecated use {@link GlobalActions} instead.
- */
-public class PowerDialog extends Dialog implements OnClickListener,
- OnKeyListener {
- private static final String TAG = "PowerDialog";
-
- static private StatusBarManager sStatusBar;
- private Button mKeyguard;
- private Button mPower;
- private Button mRadioPower;
- private Button mSilent;
-
- private LocalPowerManager mPowerManager;
-
- public PowerDialog(Context context, LocalPowerManager powerManager) {
- super(context);
- mPowerManager = powerManager;
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- Context context = getContext();
-
- if (sStatusBar == null) {
- sStatusBar = (StatusBarManager)context.getSystemService(Context.STATUS_BAR_SERVICE);
- }
-
- setContentView(com.android.internal.R.layout.power_dialog);
-
- getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
- getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
- WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
- getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
- WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
-
- setTitle(context.getText(R.string.power_dialog));
-
- mKeyguard = (Button) findViewById(R.id.keyguard);
- mPower = (Button) findViewById(R.id.off);
- mRadioPower = (Button) findViewById(R.id.radio_power);
- mSilent = (Button) findViewById(R.id.silent);
-
- if (mKeyguard != null) {
- mKeyguard.setOnKeyListener(this);
- mKeyguard.setOnClickListener(this);
- }
- if (mPower != null) {
- mPower.setOnClickListener(this);
- }
- if (mRadioPower != null) {
- mRadioPower.setOnClickListener(this);
- }
- if (mSilent != null) {
- mSilent.setOnClickListener(this);
- // XXX: HACK for now hide the silent until we get mute support
- mSilent.setVisibility(View.GONE);
- }
-
- CharSequence text;
-
- // set the keyguard button's text
- text = context.getText(R.string.screen_lock);
- mKeyguard.setText(text);
- mKeyguard.requestFocus();
-
- try {
- ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
- if (phone != null) {
- text = phone.isRadioOn() ? context
- .getText(R.string.turn_off_radio) : context
- .getText(R.string.turn_on_radio);
- }
- } catch (RemoteException ex) {
- // ignore it
- }
-
- mRadioPower.setText(text);
- }
-
- public void onClick(View v) {
- this.dismiss();
- if (v == mPower) {
- // shutdown by making sure radio and power are handled accordingly.
- ShutdownThread.shutdownAfterDisablingRadio(getContext(), true);
- } else if (v == mRadioPower) {
- try {
- ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
- if (phone != null) {
- phone.toggleRadioOnOff();
- }
- } catch (RemoteException ex) {
- // ignore it
- }
- } else if (v == mSilent) {
- // do something
- } else if (v == mKeyguard) {
- if (v.isInTouchMode()) {
- // only in touch mode for the reasons explained in onKey.
- this.dismiss();
- mPowerManager.goToSleep(SystemClock.uptimeMillis() + 1);
- }
- }
- }
-
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- // The activate keyguard button needs to put the device to sleep on the
- // key up event. If we try to put it to sleep on the click or down
- // action
- // the the up action will cause the device to wake back up.
-
- // Log.i(TAG, "keyCode: " + keyCode + " action: " + event.getAction());
- if (keyCode != KeyEvent.KEYCODE_DPAD_CENTER
- || event.getAction() != KeyEvent.ACTION_UP) {
- // Log.i(TAG, "getting out of dodge...");
- return false;
- }
-
- // Log.i(TAG, "Clicked mKeyguard! dimissing dialog");
- this.dismiss();
- // Log.i(TAG, "onKey: turning off the screen...");
- // XXX: This is a hack for now
- mPowerManager.goToSleep(event.getEventTime() + 1);
- return true;
- }
-
- public void show() {
- super.show();
- Log.d(TAG, "show... disabling expand");
- sStatusBar.disable(StatusBarManager.DISABLE_EXPAND);
- }
-
- public void dismiss() {
- super.dismiss();
- Log.d(TAG, "dismiss... reenabling expand");
- sStatusBar.disable(StatusBarManager.DISABLE_NONE);
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import android.app.ActivityManager;
-import android.app.Dialog;
-import android.app.StatusBarManager;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.view.View;
-import android.view.Window;
-import android.view.WindowManager;
-import android.view.View.OnClickListener;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import java.util.List;
-
-public class RecentApplicationsDialog extends Dialog implements OnClickListener {
- // Elements for debugging support
-// private static final String LOG_TAG = "RecentApplicationsDialog";
- private static final boolean DBG_FORCE_EMPTY_LIST = false;
-
- static private StatusBarManager sStatusBar;
-
- private static final int NUM_BUTTONS = 6;
- private static final int MAX_RECENT_TASKS = NUM_BUTTONS * 2; // allow for some discards
-
- final View[] mButtons = new View[NUM_BUTTONS];
- View mNoAppsText;
- IntentFilter mBroadcastIntentFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
-
- public RecentApplicationsDialog(Context context) {
- super(context);
- }
-
- /**
- * We create the recent applications dialog just once, and it stays around (hidden)
- * until activated by the user.
- *
- * @see PhoneWindowManager#showRecentAppsDialog
- */
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- Context context = getContext();
-
- if (sStatusBar == null) {
- sStatusBar = (StatusBarManager)context.getSystemService(Context.STATUS_BAR_SERVICE);
- }
-
- Window theWindow = getWindow();
- theWindow.requestFeature(Window.FEATURE_NO_TITLE);
- theWindow.setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
- theWindow.setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
- WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
- theWindow.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
- WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
-
- setContentView(com.android.internal.R.layout.recent_apps_dialog);
-
- mButtons[0] = findViewById(com.android.internal.R.id.button1);
- mButtons[1] = findViewById(com.android.internal.R.id.button2);
- mButtons[2] = findViewById(com.android.internal.R.id.button3);
- mButtons[3] = findViewById(com.android.internal.R.id.button4);
- mButtons[4] = findViewById(com.android.internal.R.id.button5);
- mButtons[5] = findViewById(com.android.internal.R.id.button6);
- mNoAppsText = findViewById(com.android.internal.R.id.no_applications_message);
-
- for (View b : mButtons) {
- b.setOnClickListener(this);
- }
- }
-
- /**
- * Handler for user clicks. If a button was clicked, launch the corresponding activity.
- */
- public void onClick(View v) {
-
- for (View b : mButtons) {
- if (b == v) {
- // prepare a launch intent and send it
- Intent intent = (Intent)b.getTag();
- intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
- getContext().startActivity(intent);
- }
- }
- dismiss();
- }
-
- /**
- * Set up and show the recent activities dialog.
- */
- @Override
- public void onStart() {
- super.onStart();
- reloadButtons();
- if (sStatusBar != null) {
- sStatusBar.disable(StatusBarManager.DISABLE_EXPAND);
- }
-
- // receive broadcasts
- getContext().registerReceiver(mBroadcastReceiver, mBroadcastIntentFilter);
- }
-
- /**
- * Dismiss the recent activities dialog.
- */
- @Override
- public void onStop() {
- super.onStop();
-
- // dump extra memory we're hanging on to
- for (View b : mButtons) {
- setButtonAppearance(b, null, null);
- b.setTag(null);
- }
-
- if (sStatusBar != null) {
- sStatusBar.disable(StatusBarManager.DISABLE_NONE);
- }
-
- // stop receiving broadcasts
- getContext().unregisterReceiver(mBroadcastReceiver);
- }
-
- /**
- * Reload the 6 buttons with recent activities
- */
- private void reloadButtons() {
-
- final Context context = getContext();
- final PackageManager pm = context.getPackageManager();
- final ActivityManager am = (ActivityManager)
- context.getSystemService(Context.ACTIVITY_SERVICE);
- final List<ActivityManager.RecentTaskInfo> recentTasks =
- am.getRecentTasks(MAX_RECENT_TASKS, 0);
-
- ResolveInfo homeInfo = pm.resolveActivity(
- new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME),
- 0);
-
- // Performance note: Our android performance guide says to prefer Iterator when
- // using a List class, but because we know that getRecentTasks() always returns
- // an ArrayList<>, we'll use a simple index instead.
- int button = 0;
- int numTasks = recentTasks.size();
- for (int i = 0; i < numTasks && (button < NUM_BUTTONS); ++i) {
- final ActivityManager.RecentTaskInfo info = recentTasks.get(i);
-
- // for debug purposes only, disallow first result to create empty lists
- if (DBG_FORCE_EMPTY_LIST && (i == 0)) continue;
-
- Intent intent = new Intent(info.baseIntent);
- if (info.origActivity != null) {
- intent.setComponent(info.origActivity);
- }
-
- // Skip the current home activity.
- if (homeInfo != null) {
- if (homeInfo.activityInfo.packageName.equals(
- intent.getComponent().getPackageName())
- && homeInfo.activityInfo.name.equals(
- intent.getComponent().getClassName())) {
- continue;
- }
- }
-
- intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
- | Intent.FLAG_ACTIVITY_NEW_TASK);
- final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
- if (resolveInfo != null) {
- final ActivityInfo activityInfo = resolveInfo.activityInfo;
- final String title = activityInfo.loadLabel(pm).toString();
- final Drawable icon = activityInfo.loadIcon(pm);
-
- if (title != null && title.length() > 0 && icon != null) {
- final View b = mButtons[button];
- setButtonAppearance(b, title, icon);
- b.setTag(intent);
- b.setVisibility(View.VISIBLE);
- b.setPressed(false);
- b.clearFocus();
- ++button;
- }
- }
- }
-
- // handle the case of "no icons to show"
- mNoAppsText.setVisibility((button == 0) ? View.VISIBLE : View.GONE);
-
- // hide the rest
- for ( ; button < NUM_BUTTONS; ++button) {
- mButtons[button].setVisibility(View.GONE);
- }
- }
-
- /**
- * Adjust appearance of each icon-button
- */
- private void setButtonAppearance(View theButton, final String theTitle, final Drawable icon) {
- TextView tv = (TextView) theButton.findViewById(com.android.internal.R.id.label);
- tv.setText(theTitle);
- ImageView iv = (ImageView) theButton.findViewById(com.android.internal.R.id.icon);
- iv.setImageDrawable(icon);
- }
-
- /**
- * This is the listener for the ACTION_CLOSE_SYSTEM_DIALOGS intent. It's an indication that
- * we should close ourselves immediately, in order to allow a higher-priority UI to take over
- * (e.g. phone call received).
- *
- * TODO: This is a really heavyweight solution for something that should be so simple.
- * For example, we already have a handler, in our superclass, why aren't we sharing that?
- * I think we need to investigate simplifying this entire methodology, or perhaps boosting
- * it up into the Dialog class.
- */
- private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
- String reason = intent.getStringExtra(PhoneWindowManager.SYSTEM_DIALOG_REASON_KEY);
- if (! PhoneWindowManager.SYSTEM_DIALOG_REASON_RECENT_APPS.equals(reason)) {
- dismiss();
- }
- }
- }
- };
-}
+++ /dev/null
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import android.content.Context;
-import android.content.Intent;
-import android.database.ContentObserver;
-import android.database.Cursor;
-import android.os.Handler;
-import android.provider.Settings;
-import android.util.Log;
-import android.util.SparseArray;
-import android.view.KeyCharacterMap;
-
-import java.net.URISyntaxException;
-
-/**
- * Manages quick launch shortcuts by:
- * <li> Keeping the local copy in sync with the database (this is an observer)
- * <li> Returning a shortcut-matching intent to clients
- */
-class ShortcutManager extends ContentObserver {
-
- private static final String TAG = "ShortcutManager";
-
- private static final int COLUMN_SHORTCUT = 0;
- private static final int COLUMN_INTENT = 1;
- private static final String[] sProjection = new String[] {
- Settings.Bookmarks.SHORTCUT, Settings.Bookmarks.INTENT
- };
-
- private Context mContext;
- private Cursor mCursor;
- /** Map of a shortcut to its intent. */
- private SparseArray<Intent> mShortcutIntents;
-
- public ShortcutManager(Context context, Handler handler) {
- super(handler);
-
- mContext = context;
- mShortcutIntents = new SparseArray<Intent>();
- }
-
- /** Observes the provider of shortcut+intents */
- public void observe() {
- mCursor = mContext.getContentResolver().query(
- Settings.Bookmarks.CONTENT_URI, sProjection, null, null, null);
- mCursor.registerContentObserver(this);
- updateShortcuts();
- }
-
- @Override
- public void onChange(boolean selfChange) {
- updateShortcuts();
- }
-
- private void updateShortcuts() {
- Cursor c = mCursor;
- if (!c.requery()) {
- Log.e(TAG, "ShortcutObserver could not re-query shortcuts.");
- return;
- }
-
- mShortcutIntents.clear();
- while (c.moveToNext()) {
- int shortcut = c.getInt(COLUMN_SHORTCUT);
- if (shortcut == 0) continue;
- String intentURI = c.getString(COLUMN_INTENT);
- Intent intent = null;
- try {
- intent = Intent.getIntent(intentURI);
- } catch (URISyntaxException e) {
- Log.w(TAG, "Intent URI for shortcut invalid.", e);
- }
- if (intent == null) continue;
- mShortcutIntents.put(shortcut, intent);
- }
- }
-
- /**
- * Gets the shortcut intent for a given keycode+modifier. Make sure you
- * strip whatever modifier is used for invoking shortcuts (for example,
- * if 'Sym+A' should invoke a shortcut on 'A', you should strip the
- * 'Sym' bit from the modifiers before calling this method.
- * <p>
- * This will first try an exact match (with modifiers), and then try a
- * match without modifiers (primary character on a key).
- *
- * @param keyCode The keycode of the key pushed.
- * @param modifiers The modifiers without any that are used for chording
- * to invoke a shortcut.
- * @return The intent that matches the shortcut, or null if not found.
- */
- public Intent getIntent(int keyCode, int modifiers) {
- KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.BUILT_IN_KEYBOARD);
- // First try the exact keycode (with modifiers)
- int shortcut = kcm.get(keyCode, modifiers);
- Intent intent = shortcut != 0 ? mShortcutIntents.get(shortcut) : null;
- if (intent != null) return intent;
-
- // Next try the keycode without modifiers (the primary character on that key)
- shortcut = Character.toLowerCase(kcm.get(keyCode, 0));
- return shortcut != 0 ? mShortcutIntents.get(shortcut) : null;
- }
-
-}
+++ /dev/null
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package com.android.internal.policy.impl;
-
-import android.app.ProgressDialog;
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.os.RemoteException;
-import android.os.Power;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import com.android.internal.telephony.ITelephony;
-import android.util.Log;
-import android.view.WindowManager;
-
-
-final class ShutdownThread extends Thread {
- // constants
- private static final String TAG = "ShutdownThread";
- private static final int MAX_NUM_PHONE_STATE_READS = 16;
- private static final int PHONE_STATE_POLL_SLEEP_MSEC = 500;
- private static final ITelephony sPhone =
- ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
-
- // state tracking
- private static Object sIsStartedGuard = new Object();
- private static boolean sIsStarted = false;
-
- // static instance of this thread
- private static final ShutdownThread sInstance = new ShutdownThread();
-
- private ShutdownThread() {
- }
-
- /**
- * request a shutdown.
- *
- * @param context Context used to display the shutdown progress dialog.
- */
- public static void shutdownAfterDisablingRadio(final Context context, boolean confirm){
- // ensure that only one thread is trying to power down.
- // any additional calls are just returned
- synchronized (sIsStartedGuard){
- if (sIsStarted) {
- Log.d(TAG, "Request to shutdown already running, returning.");
- return;
- }
- }
-
- Log.d(TAG, "Notifying thread to start radio shutdown");
-
- if (confirm) {
- final AlertDialog dialog = new AlertDialog.Builder(context)
- .setIcon(android.R.drawable.ic_dialog_alert)
- .setTitle(com.android.internal.R.string.power_off)
- .setMessage(com.android.internal.R.string.shutdown_confirm)
- .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- beginShutdownSequence(context);
- }
- })
- .setNegativeButton(com.android.internal.R.string.no, null)
- .create();
- dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
- dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
- dialog.show();
- } else {
- beginShutdownSequence(context);
- }
- }
-
- private static void beginShutdownSequence(Context context) {
- synchronized (sIsStartedGuard) {
- sIsStarted = true;
- }
-
- // throw up an indeterminate system dialog to indicate radio is
- // shutting down.
- ProgressDialog pd = new ProgressDialog(context);
- pd.setTitle(context.getText(com.android.internal.R.string.power_off));
- pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
- pd.setIndeterminate(true);
- pd.setCancelable(false);
- pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
- pd.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
-
- pd.show();
-
- // start the thread that initiates shutdown
- sInstance.start();
- }
-
- /**
- * Makes sure we handle the shutdown gracefully.
- * Shuts off power regardless of radio state if the alloted time has passed.
- */
- public void run() {
- //shutdown the phone radio if possible.
- if (sPhone != null) {
- try {
- //shutdown radio
- sPhone.setRadio(false);
-
- for (int i = 0; i < MAX_NUM_PHONE_STATE_READS; i++){
- // poll radio up to 64 times, with a 0.5 sec delay between each call,
- // totaling 32 sec.
- if (!sPhone.isRadioOn()) {
- Log.d(TAG, "Radio shutdown complete.");
- break;
- }
- SystemClock.sleep(PHONE_STATE_POLL_SLEEP_MSEC);
- }
- } catch (RemoteException ex) {
- Log.e(TAG, "RemoteException caught from failed radio shutdown.", ex);
- }
- }
-
- //shutdown power
- Log.d(TAG, "Shutting down power.");
- Power.shutdown();
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import android.app.Dialog;
-import android.app.ProgressDialog;
-import android.content.Context;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import com.android.internal.telephony.ITelephony;
-import android.text.Editable;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.WindowManager;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-import com.android.internal.R;
-
-/**
- * Displays a dialer like interface to unlock the SIM PIN.
- */
-public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, View.OnClickListener,
- KeyguardUpdateMonitor.ConfigurationChangeCallback {
-
- private static final int DIGIT_PRESS_WAKE_MILLIS = 5000;
-
- private final KeyguardUpdateMonitor mUpdateMonitor;
- private final KeyguardScreenCallback mCallback;
-
- private final boolean mCreatedWithKeyboardOpen;
-
- private TextView mHeaderText;
- private EditText mPinText;
-
- private TextView mOkButton;
- private TextView mEmergencyCallButton;
-
- private View mBackSpaceButton;
-
- private final int[] mEnteredPin = {0, 0, 0, 0, 0, 0, 0, 0};
- private int mEnteredDigits = 0;
-
- private ProgressDialog mSimUnlockProgressDialog = null;
-
- private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
-
- public SimUnlockScreen(Context context, KeyguardUpdateMonitor updateMonitor,
- KeyguardScreenCallback callback) {
- super(context);
- mUpdateMonitor = updateMonitor;
- mCallback = callback;
- mCreatedWithKeyboardOpen = mUpdateMonitor.isKeyboardOpen();
-
- if (mCreatedWithKeyboardOpen) {
- LayoutInflater.from(context).inflate(R.layout.keyguard_screen_sim_pin_landscape, this, true);
- } else {
- LayoutInflater.from(context).inflate(R.layout.keyguard_screen_sim_pin_portrait, this, true);
- new TouchInput();
- }
-
- mHeaderText = (TextView) findViewById(R.id.headerText);
- mPinText = (EditText) findViewById(R.id.pinDisplay);
- mBackSpaceButton = findViewById(R.id.backspace);
- mBackSpaceButton.setOnClickListener(this);
-
- mEmergencyCallButton = (TextView) findViewById(R.id.emergencyCall);
- mOkButton = (TextView) findViewById(R.id.ok);
-
- mHeaderText.setText(R.string.keyguard_password_enter_pin_code);
- mPinText.setFocusable(false);
-
- mEmergencyCallButton.setOnClickListener(this);
- mOkButton.setOnClickListener(this);
-
- mUpdateMonitor.registerConfigurationChangeCallback(this);
- setFocusableInTouchMode(true);
- }
-
- /** {@inheritDoc} */
- public boolean needsInput() {
- return true;
- }
-
- /** {@inheritDoc} */
- public void onPause() {
-
- }
-
- /** {@inheritDoc} */
- public void onResume() {
- // start fresh
- mHeaderText.setText(R.string.keyguard_password_enter_pin_code);
-
- // make sure that the number of entered digits is consistent when we
- // erase the SIM unlock code, including orientation changes.
- mPinText.setText("");
- mEnteredDigits = 0;
- }
-
- /** {@inheritDoc} */
- public void cleanUp() {
- // hide the dialog.
- if (mSimUnlockProgressDialog != null) {
- mSimUnlockProgressDialog.hide();
- }
- mUpdateMonitor.removeCallback(this);
- }
-
-
- /**
- * Since the IPC can block, we want to run the request in a separate thread
- * with a callback.
- */
- private abstract class CheckSimPin extends Thread {
-
- private final String mPin;
-
- protected CheckSimPin(String pin) {
- mPin = pin;
- }
-
- abstract void onSimLockChangedResponse(boolean success);
-
- @Override
- public void run() {
- try {
- final boolean result = ITelephony.Stub.asInterface(ServiceManager
- .checkService("phone")).supplyPin(mPin);
- post(new Runnable() {
- public void run() {
- onSimLockChangedResponse(result);
- }
- });
- } catch (RemoteException e) {
- post(new Runnable() {
- public void run() {
- onSimLockChangedResponse(false);
- }
- });
- }
- }
- }
-
- public void onClick(View v) {
- if (v == mBackSpaceButton) {
- final Editable digits = mPinText.getText();
- final int len = digits.length();
- if (len > 0) {
- digits.delete(len-1, len);
- mEnteredDigits--;
- }
- mCallback.pokeWakelock();
- } else if (v == mEmergencyCallButton) {
- mCallback.takeEmergencyCallAction();
- } else if (v == mOkButton) {
- checkPin();
- }
- }
-
- private Dialog getSimUnlockProgressDialog() {
- if (mSimUnlockProgressDialog == null) {
- mSimUnlockProgressDialog = new ProgressDialog(mContext);
- mSimUnlockProgressDialog.setMessage(
- mContext.getString(R.string.lockscreen_sim_unlock_progress_dialog_message));
- mSimUnlockProgressDialog.setIndeterminate(true);
- mSimUnlockProgressDialog.setCancelable(false);
- mSimUnlockProgressDialog.getWindow().setType(
- WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
- mSimUnlockProgressDialog.getWindow().setFlags(
- WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
- WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
- }
- return mSimUnlockProgressDialog;
- }
-
- private void checkPin() {
-
- // make sure that the pin is at least 4 digits long.
- if (mEnteredDigits < 4) {
- // otherwise, display a message to the user, and don't submit.
- mHeaderText.setText(R.string.invalidPin);
- mPinText.setText("");
- mEnteredDigits = 0;
- mCallback.pokeWakelock();
- return;
- }
- getSimUnlockProgressDialog().show();
-
- new CheckSimPin(mPinText.getText().toString()) {
- void onSimLockChangedResponse(boolean success) {
- if (mSimUnlockProgressDialog != null) {
- mSimUnlockProgressDialog.hide();
- }
- if (success) {
- // before closing the keyguard, report back that
- // the sim is unlocked so it knows right away
- mUpdateMonitor.reportSimPinUnlocked();
- mCallback.goToUnlockScreen();
- } else {
- mHeaderText.setText(R.string.keyguard_password_wrong_pin_code);
- mPinText.setText("");
- mEnteredDigits = 0;
- mCallback.pokeWakelock();
- }
- }
- }.start();
- }
-
-
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_BACK) {
- mCallback.goToLockScreen();
- return true;
- }
-
- final char match = event.getMatch(DIGITS);
- if (match != 0) {
- reportDigit(match - '0');
- return true;
- }
- if (keyCode == KeyEvent.KEYCODE_DEL) {
- if (mEnteredDigits > 0) {
- mPinText.onKeyDown(keyCode, event);
- mEnteredDigits--;
- }
- return true;
- }
-
- if (keyCode == KeyEvent.KEYCODE_ENTER) {
- checkPin();
- return true;
- }
-
- return false;
- }
-
- private void reportDigit(int digit) {
- if (mEnteredDigits == 0) {
- mPinText.setText("");
- }
- if (mEnteredDigits == 8) {
- return;
- }
- mPinText.append(Integer.toString(digit));
- mEnteredPin[mEnteredDigits++] = digit;
- }
-
- public void onOrientationChange(boolean inPortrait) {}
-
- public void onKeyboardChange(boolean isKeyboardOpen) {
- if (isKeyboardOpen != mCreatedWithKeyboardOpen) {
- mCallback.recreateMe();
- }
- }
-
- /**
- * Helper class to handle input from touch dialer. Only relevant when
- * the keyboard is shut.
- */
- private class TouchInput implements View.OnClickListener {
- private TextView mZero;
- private TextView mOne;
- private TextView mTwo;
- private TextView mThree;
- private TextView mFour;
- private TextView mFive;
- private TextView mSix;
- private TextView mSeven;
- private TextView mEight;
- private TextView mNine;
- private TextView mCancelButton;
-
- private TouchInput() {
- mZero = (TextView) findViewById(R.id.zero);
- mOne = (TextView) findViewById(R.id.one);
- mTwo = (TextView) findViewById(R.id.two);
- mThree = (TextView) findViewById(R.id.three);
- mFour = (TextView) findViewById(R.id.four);
- mFive = (TextView) findViewById(R.id.five);
- mSix = (TextView) findViewById(R.id.six);
- mSeven = (TextView) findViewById(R.id.seven);
- mEight = (TextView) findViewById(R.id.eight);
- mNine = (TextView) findViewById(R.id.nine);
- mCancelButton = (TextView) findViewById(R.id.cancel);
-
- mZero.setText("0");
- mOne.setText("1");
- mTwo.setText("2");
- mThree.setText("3");
- mFour.setText("4");
- mFive.setText("5");
- mSix.setText("6");
- mSeven.setText("7");
- mEight.setText("8");
- mNine.setText("9");
-
- mZero.setOnClickListener(this);
- mOne.setOnClickListener(this);
- mTwo.setOnClickListener(this);
- mThree.setOnClickListener(this);
- mFour.setOnClickListener(this);
- mFive.setOnClickListener(this);
- mSix.setOnClickListener(this);
- mSeven.setOnClickListener(this);
- mEight.setOnClickListener(this);
- mNine.setOnClickListener(this);
- mCancelButton.setOnClickListener(this);
- }
-
-
- public void onClick(View v) {
- if (v == mCancelButton) {
- mCallback.goToLockScreen();
- return;
- }
-
- final int digit = checkDigit(v);
- if (digit >= 0) {
- mCallback.pokeWakelock(DIGIT_PRESS_WAKE_MILLIS);
- reportDigit(digit);
- }
- }
-
- private int checkDigit(View v) {
- int digit = -1;
- if (v == mZero) {
- digit = 0;
- } else if (v == mOne) {
- digit = 1;
- } else if (v == mTwo) {
- digit = 2;
- } else if (v == mThree) {
- digit = 3;
- } else if (v == mFour) {
- digit = 4;
- } else if (v == mFive) {
- digit = 5;
- } else if (v == mSix) {
- digit = 6;
- } else if (v == mSeven) {
- digit = 7;
- } else if (v == mEight) {
- digit = 8;
- } else if (v == mNine) {
- digit = 9;
- }
- return digit;
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.policy.impl;
-
-import android.content.Context;
-import android.content.ServiceConnection;
-import android.os.CountDownTimer;
-import android.os.SystemClock;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.MotionEvent;
-import android.widget.Button;
-import android.widget.ImageView;
-import android.widget.TextView;
-import com.android.internal.R;
-import com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.internal.widget.LockPatternView;
-
-import java.util.List;
-
-/**
- * This is the screen that shows the 9 circle unlock widget and instructs
- * the user how to unlock their device, or make an emergency call.
- */
-class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient
- implements KeyguardScreen, KeyguardUpdateMonitor.ConfigurationChangeCallback {
-
- private static final String TAG = "UnlockScreen";
-
- // how long before we clear the wrong pattern
- private static final int PATTERN_CLEAR_TIMEOUT_MS = 2000;
-
- // how long we stay awake once the user is ready to enter a pattern
- private static final int UNLOCK_PATTERN_WAKE_INTERVAL_MS = 7000;
-
- private int mFailedPatternAttemptsSinceLastTimeout = 0;
- private int mTotalFailedPatternAttempts = 0;
- private CountDownTimer mCountdownTimer = null;
-
- private final LockPatternUtils mLockPatternUtils;
- private final KeyguardUpdateMonitor mUpdateMonitor;
- private final KeyguardScreenCallback mCallback;
-
- private boolean mCreatedInPortrait;
-
- private ImageView mUnlockIcon;
- private TextView mUnlockHeader;
- private LockPatternView mLockPatternView;
-
- private ViewGroup mFooterNormal;
- private ViewGroup mFooterForgotPattern;
-
- /**
- * Keeps track of the last time we poked the wake lock during dispatching
- * of the touch event, initalized to something gauranteed to make us
- * poke it when the user starts drawing the pattern.
- * @see #dispatchTouchEvent(android.view.MotionEvent)
- */
- private long mLastPokeTime = -UNLOCK_PATTERN_WAKE_INTERVAL_MS;
-
- /**
- * Useful for clearing out the wrong pattern after a delay
- */
- private Runnable mCancelPatternRunnable = new Runnable() {
- public void run() {
- mLockPatternView.clearPattern();
- }
- };
-
- private Button mForgotPatternButton;
-
- private ServiceConnection mServiceConnection;
-
-
- enum FooterMode {
- Normal,
- ForgotLockPattern,
- VerifyUnlocked
- }
-
- private void updateFooter(FooterMode mode) {
- switch (mode) {
- case Normal:
- mFooterNormal.setVisibility(View.VISIBLE);
- mFooterForgotPattern.setVisibility(View.GONE);
- break;
- case ForgotLockPattern:
- mFooterNormal.setVisibility(View.GONE);
- mFooterForgotPattern.setVisibility(View.VISIBLE);
- break;
- case VerifyUnlocked:
- mFooterNormal.setVisibility(View.GONE);
- mFooterForgotPattern.setVisibility(View.GONE);
- }
- }
-
- /**
- * @param context The context.
- * @param lockPatternUtils Used to lookup lock pattern settings.
- * @param updateMonitor Used to lookup state affecting keyguard.
- * @param callback Used to notify the manager when we're done, etc.
- * @param totalFailedAttempts The current number of failed attempts.
- */
- UnlockScreen(Context context,
- LockPatternUtils lockPatternUtils,
- KeyguardUpdateMonitor updateMonitor,
- KeyguardScreenCallback callback,
- int totalFailedAttempts) {
- super(context);
- mLockPatternUtils = lockPatternUtils;
- mUpdateMonitor = updateMonitor;
- mCallback = callback;
- mTotalFailedPatternAttempts = totalFailedAttempts;
- mFailedPatternAttemptsSinceLastTimeout = totalFailedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT;
-
- if (mUpdateMonitor.isInPortrait()) {
- LayoutInflater.from(context).inflate(R.layout.keyguard_screen_unlock_portrait, this, true);
- } else {
- LayoutInflater.from(context).inflate(R.layout.keyguard_screen_unlock_landscape, this, true);
- }
-
- mUnlockIcon = (ImageView) findViewById(R.id.unlockLockIcon);
-
- mLockPatternView = (LockPatternView) findViewById(R.id.lockPattern);
- mUnlockHeader = (TextView) findViewById(R.id.headerText);
-
- mUnlockHeader.setText(R.string.lockscreen_pattern_instructions);
-
- mFooterNormal = (ViewGroup) findViewById(R.id.footerNormal);
- mFooterForgotPattern = (ViewGroup) findViewById(R.id.footerForgotPattern);
-
- // emergency call buttons
- final OnClickListener emergencyClick = new OnClickListener() {
- public void onClick(View v) {
- mCallback.takeEmergencyCallAction();
- }
- };
- Button emergencyAlone = (Button) findViewById(R.id.emergencyCallAlone);
- emergencyAlone.setFocusable(false); // touch only!
- emergencyAlone.setOnClickListener(emergencyClick);
- Button emergencyTogether = (Button) findViewById(R.id.emergencyCallTogether);
- emergencyTogether.setFocusable(false);
- emergencyTogether.setOnClickListener(emergencyClick);
-
- mForgotPatternButton = (Button) findViewById(R.id.forgotPattern);
- mForgotPatternButton.setText(R.string.lockscreen_forgot_pattern_button_text);
- mForgotPatternButton.setOnClickListener(new OnClickListener() {
-
- public void onClick(View v) {
- mLockPatternUtils.setPermanentlyLocked(true);
- mCallback.goToUnlockScreen();
- }
- });
-
- // make it so unhandled touch events within the unlock screen go to the
- // lock pattern view.
- setDefaultTouchRecepient(mLockPatternView);
-
- mLockPatternView.setSaveEnabled(false);
- mLockPatternView.setFocusable(false);
- mLockPatternView.setOnPatternListener(new UnlockPatternListener());
-
- // stealth mode will be the same for the life of this screen
- mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled());
-
- // vibrate mode will be the same for the life of this screen
- mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled());
-
- // assume normal footer mode for now
- updateFooter(FooterMode.Normal);
-
- mCreatedInPortrait = updateMonitor.isInPortrait();
- updateMonitor.registerConfigurationChangeCallback(this);
- setFocusableInTouchMode(true);
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_BACK) {
- mCallback.goToLockScreen();
- return true;
- }
- return false;
- }
-
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev) {
- // as long as the user is entering a pattern (i.e sending a touch
- // event that was handled by this screen), keep poking the
- // wake lock so that the screen will stay on.
- final boolean result = super.dispatchTouchEvent(ev);
- if (result &&
- ((SystemClock.elapsedRealtime() - mLastPokeTime)
- > (UNLOCK_PATTERN_WAKE_INTERVAL_MS - 100))) {
- mLastPokeTime = SystemClock.elapsedRealtime();
- mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS);
- }
- return result;
- }
-
- /** {@inheritDoc} */
- public void onOrientationChange(boolean inPortrait) {
- if (inPortrait != mCreatedInPortrait) {
- mCallback.recreateMe();
- }
- }
-
- /** {@inheritDoc} */
- public void onKeyboardChange(boolean isKeyboardOpen) {}
-
- /** {@inheritDoc} */
- public boolean needsInput() {
- return false;
- }
-
- /** {@inheritDoc} */
- public void onPause() {
- if (mCountdownTimer != null) {
- mCountdownTimer.cancel();
- mCountdownTimer = null;
- }
- }
-
- /** {@inheritDoc} */
- public void onResume() {
- // reset header
- mUnlockHeader.setText(R.string.lockscreen_pattern_instructions);
- mUnlockIcon.setVisibility(View.VISIBLE);
-
- // reset lock pattern
- mLockPatternView.enableInput();
- mLockPatternView.setEnabled(true);
- mLockPatternView.clearPattern();
-
- // show "forgot pattern?" button if we have an alternate authentication method
- mForgotPatternButton.setVisibility(mCallback.doesFallbackUnlockScreenExist()
- ? View.VISIBLE : View.INVISIBLE);
-
- // if the user is currently locked out, enforce it.
- long deadline = mLockPatternUtils.getLockoutAttemptDeadline();
- if (deadline != 0) {
- handleAttemptLockout(deadline);
- }
-
- // the footer depends on how many total attempts the user has failed
- if (mCallback.isVerifyUnlockOnly()) {
- updateFooter(FooterMode.VerifyUnlocked);
- } else if (mTotalFailedPatternAttempts < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) {
- updateFooter(FooterMode.Normal);
- } else {
- updateFooter(FooterMode.ForgotLockPattern);
- }
- }
-
- /** {@inheritDoc} */
- public void cleanUp() {
- mUpdateMonitor.removeCallback(this);
- }
-
- private class UnlockPatternListener
- implements LockPatternView.OnPatternListener {
-
- public void onPatternStart() {
- mLockPatternView.removeCallbacks(mCancelPatternRunnable);
- }
-
- public void onPatternCleared() {
- }
-
- public void onPatternDetected(List<LockPatternView.Cell> pattern) {
- if (mLockPatternUtils.checkPattern(pattern)) {
- mLockPatternView
- .setDisplayMode(LockPatternView.DisplayMode.Correct);
- mUnlockIcon.setVisibility(View.GONE);
- mUnlockHeader.setText(R.string.lockscreen_pattern_correct);
- mCallback.keyguardDone(true);
- } else {
- mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS);
- mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong);
- if (pattern.size() >= LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) {
- mTotalFailedPatternAttempts++;
- mFailedPatternAttemptsSinceLastTimeout++;
- mCallback.reportFailedPatternAttempt();
- }
- if (mFailedPatternAttemptsSinceLastTimeout >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) {
- long deadline = mLockPatternUtils.setLockoutAttemptDeadline();
- handleAttemptLockout(deadline);
- return;
- }
- mUnlockIcon.setVisibility(View.VISIBLE);
- mUnlockHeader.setText(R.string.lockscreen_pattern_wrong);
- mLockPatternView.postDelayed(
- mCancelPatternRunnable,
- PATTERN_CLEAR_TIMEOUT_MS);
- }
- }
- }
-
- private void handleAttemptLockout(long elapsedRealtimeDeadline) {
- mLockPatternView.clearPattern();
- mLockPatternView.setEnabled(false);
- long elapsedRealtime = SystemClock.elapsedRealtime();
- mCountdownTimer = new CountDownTimer(elapsedRealtimeDeadline - elapsedRealtime, 1000) {
-
- @Override
- public void onTick(long millisUntilFinished) {
- int secondsRemaining = (int) (millisUntilFinished / 1000);
- mUnlockHeader.setText(getContext().getString(
- R.string.lockscreen_too_many_failed_attempts_countdown,
- secondsRemaining));
- }
-
- @Override
- public void onFinish() {
- mLockPatternView.setEnabled(true);
- mUnlockHeader.setText(R.string.lockscreen_pattern_instructions);
- mUnlockIcon.setVisibility(View.VISIBLE);
- mFailedPatternAttemptsSinceLastTimeout = 0;
- updateFooter(FooterMode.ForgotLockPattern);
- }
- }.start();
- }
-
-}
+++ /dev/null
-<body>
-
-{@hide}
-
-</body>