| /* |
| * 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.keyguard_obsolete; |
| |
| import com.android.internal.R; |
| import com.android.internal.telephony.IccCardConstants; |
| import com.android.internal.widget.LockPatternUtils; |
| import com.android.internal.widget.SlidingTab; |
| import com.android.internal.widget.WaveView; |
| import com.android.internal.widget.multiwaveview.GlowPadView; |
| |
| import android.app.ActivityManager; |
| import android.app.ActivityManagerNative; |
| import android.app.SearchManager; |
| import android.content.ActivityNotFoundException; |
| import android.content.ComponentName; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.res.Configuration; |
| import android.content.res.Resources; |
| import android.os.UserHandle; |
| import android.os.Vibrator; |
| import android.view.KeyEvent; |
| import android.view.LayoutInflater; |
| import android.view.View; |
| import android.view.ViewGroup; |
| import android.widget.*; |
| import android.util.Log; |
| import android.util.Slog; |
| import android.media.AudioManager; |
| import android.os.RemoteException; |
| import android.provider.MediaStore; |
| |
| import java.io.File; |
| |
| /** |
| * 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 { |
| |
| private static final int ON_RESUME_PING_DELAY = 500; // delay first ping until the screen is on |
| private static final boolean DBG = false; |
| private static final String TAG = "LockScreen"; |
| private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key"; |
| private static final int WAIT_FOR_ANIMATION_TIMEOUT = 0; |
| private static final int STAY_ON_WHILE_GRABBED_TIMEOUT = 30000; |
| private static final String ASSIST_ICON_METADATA_NAME = |
| "com.android.systemui.action_assist_icon"; |
| |
| private LockPatternUtils mLockPatternUtils; |
| private KeyguardUpdateMonitor mUpdateMonitor; |
| private KeyguardScreenCallback mCallback; |
| |
| // set to 'true' to show the ring/silence target when camera isn't available |
| private boolean mEnableRingSilenceFallback = false; |
| |
| // current configuration state of keyboard and display |
| private int mCreationOrientation; |
| |
| private boolean mSilentMode; |
| private AudioManager mAudioManager; |
| private boolean mEnableMenuKeyInLockScreen; |
| |
| private KeyguardStatusViewManager mStatusViewManager; |
| private UnlockWidgetCommonMethods mUnlockWidgetMethods; |
| private View mUnlockWidget; |
| private boolean mCameraDisabled; |
| private boolean mSearchDisabled; |
| // Is there a vibrator |
| private final boolean mHasVibrator; |
| |
| KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() { |
| |
| @Override |
| public void onRingerModeChanged(int state) { |
| boolean silent = AudioManager.RINGER_MODE_NORMAL != state; |
| if (silent != mSilentMode) { |
| mSilentMode = silent; |
| mUnlockWidgetMethods.updateResources(); |
| } |
| } |
| |
| @Override |
| public void onDevicePolicyManagerStateChanged() { |
| updateTargets(); |
| } |
| |
| @Override |
| public void onSimStateChanged(IccCardConstants.State simState) { |
| updateTargets(); |
| } |
| }; |
| |
| private interface UnlockWidgetCommonMethods { |
| // Update resources based on phone state |
| public void updateResources(); |
| |
| // Get the view associated with this widget |
| public View getView(); |
| |
| // Reset the view |
| public void reset(boolean animate); |
| |
| // Animate the widget if it supports ping() |
| public void ping(); |
| |
| // Enable or disable a target. ResourceId is the id of the *drawable* associated with the |
| // target. |
| public void setEnabled(int resourceId, boolean enabled); |
| |
| // Get the target position for the given resource. Returns -1 if not found. |
| public int getTargetPosition(int resourceId); |
| |
| // Clean up when this widget is going away |
| public void cleanUp(); |
| } |
| |
| class SlidingTabMethods implements SlidingTab.OnTriggerListener, UnlockWidgetCommonMethods { |
| private final SlidingTab mSlidingTab; |
| |
| SlidingTabMethods(SlidingTab slidingTab) { |
| mSlidingTab = slidingTab; |
| } |
| |
| public void updateResources() { |
| boolean vibe = mSilentMode |
| && (mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE); |
| |
| mSlidingTab.setRightTabResources( |
| mSilentMode ? ( vibe ? R.drawable.ic_jog_dial_vibrate_on |
| : R.drawable.ic_jog_dial_sound_off ) |
| : R.drawable.ic_jog_dial_sound_on, |
| mSilentMode ? R.drawable.jog_tab_target_yellow |
| : R.drawable.jog_tab_target_gray, |
| mSilentMode ? R.drawable.jog_tab_bar_right_sound_on |
| : R.drawable.jog_tab_bar_right_sound_off, |
| mSilentMode ? R.drawable.jog_tab_right_sound_on |
| : R.drawable.jog_tab_right_sound_off); |
| } |
| |
| /** {@inheritDoc} */ |
| public void onTrigger(View v, int whichHandle) { |
| if (whichHandle == SlidingTab.OnTriggerListener.LEFT_HANDLE) { |
| mCallback.goToUnlockScreen(); |
| } else if (whichHandle == SlidingTab.OnTriggerListener.RIGHT_HANDLE) { |
| toggleRingMode(); |
| mCallback.pokeWakelock(); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public void onGrabbedStateChange(View v, int grabbedState) { |
| if (grabbedState == SlidingTab.OnTriggerListener.RIGHT_HANDLE) { |
| mSilentMode = isSilentMode(); |
| mSlidingTab.setRightHintText(mSilentMode ? R.string.lockscreen_sound_on_label |
| : R.string.lockscreen_sound_off_label); |
| } |
| // Don't poke the wake lock when returning to a state where the handle is |
| // not grabbed since that can happen when the system (instead of the user) |
| // cancels the grab. |
| if (grabbedState != SlidingTab.OnTriggerListener.NO_HANDLE) { |
| mCallback.pokeWakelock(); |
| } |
| } |
| |
| public View getView() { |
| return mSlidingTab; |
| } |
| |
| public void reset(boolean animate) { |
| mSlidingTab.reset(animate); |
| } |
| |
| public void ping() { |
| } |
| |
| public void setEnabled(int resourceId, boolean enabled) { |
| // Not used |
| } |
| |
| public int getTargetPosition(int resourceId) { |
| return -1; // Not supported |
| } |
| |
| public void cleanUp() { |
| mSlidingTab.setOnTriggerListener(null); |
| } |
| } |
| |
| class WaveViewMethods implements WaveView.OnTriggerListener, UnlockWidgetCommonMethods { |
| |
| private final WaveView mWaveView; |
| |
| WaveViewMethods(WaveView waveView) { |
| mWaveView = waveView; |
| } |
| /** {@inheritDoc} */ |
| public void onTrigger(View v, int whichHandle) { |
| if (whichHandle == WaveView.OnTriggerListener.CENTER_HANDLE) { |
| requestUnlockScreen(); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public void onGrabbedStateChange(View v, int grabbedState) { |
| // Don't poke the wake lock when returning to a state where the handle is |
| // not grabbed since that can happen when the system (instead of the user) |
| // cancels the grab. |
| if (grabbedState == WaveView.OnTriggerListener.CENTER_HANDLE) { |
| mCallback.pokeWakelock(STAY_ON_WHILE_GRABBED_TIMEOUT); |
| } |
| } |
| |
| public void updateResources() { |
| } |
| |
| public View getView() { |
| return mWaveView; |
| } |
| public void reset(boolean animate) { |
| mWaveView.reset(); |
| } |
| public void ping() { |
| } |
| public void setEnabled(int resourceId, boolean enabled) { |
| // Not used |
| } |
| public int getTargetPosition(int resourceId) { |
| return -1; // Not supported |
| } |
| public void cleanUp() { |
| mWaveView.setOnTriggerListener(null); |
| } |
| } |
| |
| class GlowPadViewMethods implements GlowPadView.OnTriggerListener, |
| UnlockWidgetCommonMethods { |
| private final GlowPadView mGlowPadView; |
| |
| GlowPadViewMethods(GlowPadView glowPadView) { |
| mGlowPadView = glowPadView; |
| } |
| |
| public boolean isTargetPresent(int resId) { |
| return mGlowPadView.getTargetPosition(resId) != -1; |
| } |
| |
| public void updateResources() { |
| int resId; |
| if (mCameraDisabled && mEnableRingSilenceFallback) { |
| // Fall back to showing ring/silence if camera is disabled... |
| resId = mSilentMode ? R.array.lockscreen_targets_when_silent |
| : R.array.lockscreen_targets_when_soundon; |
| } else { |
| resId = R.array.lockscreen_targets_with_camera; |
| } |
| if (mGlowPadView.getTargetResourceId() != resId) { |
| mGlowPadView.setTargetResources(resId); |
| } |
| |
| // Update the search icon with drawable from the search .apk |
| if (!mSearchDisabled) { |
| Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) |
| .getAssistIntent(mContext, UserHandle.USER_CURRENT); |
| if (intent != null) { |
| // XXX Hack. We need to substitute the icon here but haven't formalized |
| // the public API. The "_google" metadata will be going away, so |
| // DON'T USE IT! |
| ComponentName component = intent.getComponent(); |
| boolean replaced = mGlowPadView.replaceTargetDrawablesIfPresent(component, |
| ASSIST_ICON_METADATA_NAME + "_google", |
| com.android.internal.R.drawable.ic_action_assist_generic); |
| |
| if (!replaced && !mGlowPadView.replaceTargetDrawablesIfPresent(component, |
| ASSIST_ICON_METADATA_NAME, |
| com.android.internal.R.drawable.ic_action_assist_generic)) { |
| Slog.w(TAG, "Couldn't grab icon from package " + component); |
| } |
| } |
| } |
| |
| setEnabled(com.android.internal.R.drawable.ic_lockscreen_camera, !mCameraDisabled); |
| setEnabled(com.android.internal.R.drawable.ic_action_assist_generic, !mSearchDisabled); |
| } |
| |
| public void onGrabbed(View v, int handle) { |
| |
| } |
| |
| public void onReleased(View v, int handle) { |
| |
| } |
| |
| public void onTrigger(View v, int target) { |
| final int resId = mGlowPadView.getResourceIdForTarget(target); |
| switch (resId) { |
| case com.android.internal.R.drawable.ic_action_assist_generic: |
| Intent assistIntent = |
| ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) |
| .getAssistIntent(mContext, UserHandle.USER_CURRENT); |
| if (assistIntent != null) { |
| launchActivity(assistIntent); |
| } else { |
| Log.w(TAG, "Failed to get intent for assist activity"); |
| } |
| mCallback.pokeWakelock(); |
| break; |
| |
| case com.android.internal.R.drawable.ic_lockscreen_camera: |
| launchActivity(new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA)); |
| mCallback.pokeWakelock(); |
| break; |
| |
| case com.android.internal.R.drawable.ic_lockscreen_silent: |
| toggleRingMode(); |
| mCallback.pokeWakelock(); |
| break; |
| |
| case com.android.internal.R.drawable.ic_lockscreen_unlock_phantom: |
| case com.android.internal.R.drawable.ic_lockscreen_unlock: |
| mCallback.goToUnlockScreen(); |
| break; |
| } |
| } |
| |
| /** |
| * Launches the said intent for the current foreground user. |
| * @param intent |
| */ |
| private void launchActivity(Intent intent) { |
| intent.setFlags( |
| Intent.FLAG_ACTIVITY_NEW_TASK |
| | Intent.FLAG_ACTIVITY_SINGLE_TOP |
| | Intent.FLAG_ACTIVITY_CLEAR_TOP); |
| try { |
| ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity(); |
| } catch (RemoteException e) { |
| Log.w(TAG, "can't dismiss keyguard on launch"); |
| } |
| try { |
| mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT)); |
| } catch (ActivityNotFoundException e) { |
| Log.w(TAG, "Activity not found for intent + " + intent.getAction()); |
| } |
| } |
| |
| public void onGrabbedStateChange(View v, int handle) { |
| // Don't poke the wake lock when returning to a state where the handle is |
| // not grabbed since that can happen when the system (instead of the user) |
| // cancels the grab. |
| if (handle != GlowPadView.OnTriggerListener.NO_HANDLE) { |
| mCallback.pokeWakelock(); |
| } |
| } |
| |
| public View getView() { |
| return mGlowPadView; |
| } |
| |
| public void reset(boolean animate) { |
| mGlowPadView.reset(animate); |
| } |
| |
| public void ping() { |
| mGlowPadView.ping(); |
| } |
| |
| public void setEnabled(int resourceId, boolean enabled) { |
| mGlowPadView.setEnableTarget(resourceId, enabled); |
| } |
| |
| public int getTargetPosition(int resourceId) { |
| return mGlowPadView.getTargetPosition(resourceId); |
| } |
| |
| public void cleanUp() { |
| mGlowPadView.setOnTriggerListener(null); |
| } |
| |
| public void onFinishFinalAnimation() { |
| |
| } |
| } |
| |
| private void requestUnlockScreen() { |
| // Delay hiding lock screen long enough for animation to finish |
| postDelayed(new Runnable() { |
| public void run() { |
| mCallback.goToUnlockScreen(); |
| } |
| }, WAIT_FOR_ANIMATION_TIMEOUT); |
| } |
| |
| private void toggleRingMode() { |
| // toggle silent mode |
| mSilentMode = !mSilentMode; |
| if (mSilentMode) { |
| mAudioManager.setRingerMode(mHasVibrator |
| ? AudioManager.RINGER_MODE_VIBRATE |
| : AudioManager.RINGER_MODE_SILENT); |
| } else { |
| mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL); |
| } |
| } |
| |
| /** |
| * In general, we enable unlocking the insecure key guard with the menu key. However, there are |
| * some cases where we wish to disable it, notably when the menu button placement or technology |
| * is prone to false positives. |
| * |
| * @return true if the menu key should be enabled |
| */ |
| private boolean shouldEnableMenuKey() { |
| final Resources res = getResources(); |
| final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen); |
| final boolean isTestHarness = ActivityManager.isRunningInTestHarness(); |
| final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists(); |
| return !configDisabled || isTestHarness || fileOverride; |
| } |
| |
| /** |
| * @param context Used to setup the view. |
| * @param configuration The current configuration. Used to use when selecting layout, etc. |
| * @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, Configuration configuration, LockPatternUtils lockPatternUtils, |
| KeyguardUpdateMonitor updateMonitor, |
| KeyguardScreenCallback callback) { |
| super(context); |
| mLockPatternUtils = lockPatternUtils; |
| mUpdateMonitor = updateMonitor; |
| mCallback = callback; |
| mEnableMenuKeyInLockScreen = shouldEnableMenuKey(); |
| mCreationOrientation = configuration.orientation; |
| |
| if (LockPatternKeyguardView.DEBUG_CONFIGURATION) { |
| Log.v(TAG, "***** CREATING LOCK SCREEN", new RuntimeException()); |
| Log.v(TAG, "Cur orient=" + mCreationOrientation |
| + " res orient=" + context.getResources().getConfiguration().orientation); |
| } |
| |
| final LayoutInflater inflater = LayoutInflater.from(context); |
| if (DBG) Log.v(TAG, "Creation orientation = " + mCreationOrientation); |
| if (mCreationOrientation != Configuration.ORIENTATION_LANDSCAPE) { |
| inflater.inflate(R.layout.keyguard_screen_tab_unlock, this, true); |
| } else { |
| inflater.inflate(R.layout.keyguard_screen_tab_unlock_land, this, true); |
| } |
| |
| mStatusViewManager = new KeyguardStatusViewManager(this, mUpdateMonitor, mLockPatternUtils, |
| mCallback, false); |
| |
| setFocusable(true); |
| setFocusableInTouchMode(true); |
| setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); |
| |
| Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); |
| mHasVibrator = vibrator == null ? false : vibrator.hasVibrator(); |
| mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); |
| mSilentMode = isSilentMode(); |
| mUnlockWidget = findViewById(R.id.unlock_widget); |
| mUnlockWidgetMethods = createUnlockMethods(mUnlockWidget); |
| |
| if (DBG) Log.v(TAG, "*** LockScreen accel is " |
| + (mUnlockWidget.isHardwareAccelerated() ? "on":"off")); |
| } |
| |
| private UnlockWidgetCommonMethods createUnlockMethods(View unlockWidget) { |
| if (unlockWidget instanceof SlidingTab) { |
| SlidingTab slidingTabView = (SlidingTab) unlockWidget; |
| slidingTabView.setHoldAfterTrigger(true, false); |
| slidingTabView.setLeftHintText(R.string.lockscreen_unlock_label); |
| slidingTabView.setLeftTabResources( |
| R.drawable.ic_jog_dial_unlock, |
| R.drawable.jog_tab_target_green, |
| R.drawable.jog_tab_bar_left_unlock, |
| R.drawable.jog_tab_left_unlock); |
| SlidingTabMethods slidingTabMethods = new SlidingTabMethods(slidingTabView); |
| slidingTabView.setOnTriggerListener(slidingTabMethods); |
| return slidingTabMethods; |
| } else if (unlockWidget instanceof WaveView) { |
| WaveView waveView = (WaveView) unlockWidget; |
| WaveViewMethods waveViewMethods = new WaveViewMethods(waveView); |
| waveView.setOnTriggerListener(waveViewMethods); |
| return waveViewMethods; |
| } else if (unlockWidget instanceof GlowPadView) { |
| GlowPadView glowPadView = (GlowPadView) unlockWidget; |
| GlowPadViewMethods glowPadViewMethods = new GlowPadViewMethods(glowPadView); |
| glowPadView.setOnTriggerListener(glowPadViewMethods); |
| return glowPadViewMethods; |
| } else { |
| throw new IllegalStateException("Unrecognized unlock widget: " + unlockWidget); |
| } |
| } |
| |
| private void updateTargets() { |
| boolean disabledByAdmin = mLockPatternUtils.getDevicePolicyManager() |
| .getCameraDisabled(null); |
| boolean disabledBySimState = mUpdateMonitor.isSimLocked(); |
| boolean cameraTargetPresent = (mUnlockWidgetMethods instanceof GlowPadViewMethods) |
| ? ((GlowPadViewMethods) mUnlockWidgetMethods) |
| .isTargetPresent(com.android.internal.R.drawable.ic_lockscreen_camera) |
| : false; |
| boolean searchTargetPresent = (mUnlockWidgetMethods instanceof GlowPadViewMethods) |
| ? ((GlowPadViewMethods) mUnlockWidgetMethods) |
| .isTargetPresent(com.android.internal.R.drawable.ic_action_assist_generic) |
| : false; |
| |
| if (disabledByAdmin) { |
| Log.v(TAG, "Camera disabled by Device Policy"); |
| } else if (disabledBySimState) { |
| Log.v(TAG, "Camera disabled by Sim State"); |
| } |
| boolean searchActionAvailable = |
| ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) |
| .getAssistIntent(mContext, UserHandle.USER_CURRENT) != null; |
| mCameraDisabled = disabledByAdmin || disabledBySimState || !cameraTargetPresent; |
| mSearchDisabled = disabledBySimState || !searchActionAvailable || !searchTargetPresent; |
| mUnlockWidgetMethods.updateResources(); |
| } |
| |
| private boolean isSilentMode() { |
| return mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL; |
| } |
| |
| @Override |
| public boolean onKeyDown(int keyCode, KeyEvent event) { |
| if (keyCode == KeyEvent.KEYCODE_MENU && mEnableMenuKeyInLockScreen) { |
| mCallback.goToUnlockScreen(); |
| } |
| return false; |
| } |
| |
| void updateConfiguration() { |
| Configuration newConfig = getResources().getConfiguration(); |
| if (newConfig.orientation != mCreationOrientation) { |
| mCallback.recreateMe(newConfig); |
| } |
| } |
| |
| @Override |
| protected void onAttachedToWindow() { |
| super.onAttachedToWindow(); |
| if (LockPatternKeyguardView.DEBUG_CONFIGURATION) { |
| Log.v(TAG, "***** LOCK ATTACHED TO WINDOW"); |
| Log.v(TAG, "Cur orient=" + mCreationOrientation |
| + ", new config=" + getResources().getConfiguration()); |
| } |
| updateConfiguration(); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| protected void onConfigurationChanged(Configuration newConfig) { |
| super.onConfigurationChanged(newConfig); |
| if (LockPatternKeyguardView.DEBUG_CONFIGURATION) { |
| Log.w(TAG, "***** LOCK CONFIG CHANGING", new RuntimeException()); |
| Log.v(TAG, "Cur orient=" + mCreationOrientation |
| + ", new config=" + newConfig); |
| } |
| updateConfiguration(); |
| } |
| |
| /** {@inheritDoc} */ |
| public boolean needsInput() { |
| return false; |
| } |
| |
| /** {@inheritDoc} */ |
| public void onPause() { |
| mUpdateMonitor.removeCallback(mInfoCallback); |
| mStatusViewManager.onPause(); |
| mUnlockWidgetMethods.reset(false); |
| } |
| |
| private final Runnable mOnResumePing = new Runnable() { |
| public void run() { |
| mUnlockWidgetMethods.ping(); |
| } |
| }; |
| |
| /** {@inheritDoc} */ |
| public void onResume() { |
| // We don't want to show the camera target if SIM state prevents us from |
| // launching the camera. So watch for SIM changes... |
| mUpdateMonitor.registerCallback(mInfoCallback); |
| |
| mStatusViewManager.onResume(); |
| postDelayed(mOnResumePing, ON_RESUME_PING_DELAY); |
| } |
| |
| /** {@inheritDoc} */ |
| public void cleanUp() { |
| mUpdateMonitor.removeCallback(mInfoCallback); // this must be first |
| mUnlockWidgetMethods.cleanUp(); |
| mLockPatternUtils = null; |
| mUpdateMonitor = null; |
| mCallback = null; |
| } |
| } |