LockScreen.java revision 6b05d58018c2806459c121e507c005639b74aee9
11f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project/*
21f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
31f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project *
41f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
51f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project * you may not use this file except in compliance with the License.
61f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project * You may obtain a copy of the License at
71f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project *
81f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
91f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project *
101f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
111f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
121f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project * See the License for the specific language governing permissions and
141f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project * limitations under the License.
151f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project */
161f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
171f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Projectpackage com.android.internal.policy.impl;
181f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
191f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Projectimport com.android.internal.R;
201f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Projectimport com.android.internal.widget.LockPatternUtils;
2180080e54ef571a5109563d4bfc4619197961f51aJim Millerimport com.android.internal.widget.SlidingTab;
223060421045d4d9e411797f91bb509824b03e33fbJim Millerimport com.android.internal.widget.WaveView;
23b505074e8273887fbcd1e933738a42e770085fb8Jim Millerimport com.android.internal.widget.multiwaveview.MultiWaveView;
241f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
253b4fcbc9f13bab6a2e9e5c37cc5e18fec7341c04Brett Chabotimport android.app.ActivityManager;
261f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Projectimport android.content.Context;
275475906f53e2d79807548932dfabbf9945143740Jim Millerimport android.content.res.Configuration;
28bd998018ed028c1922d3cf14aeabe24ff1818761Jim Millerimport android.content.res.Resources;
291f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Projectimport android.view.KeyEvent;
301f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Projectimport android.view.LayoutInflater;
311f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Projectimport android.view.View;
321f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Projectimport android.view.ViewGroup;
33d322c437fe48dc03f0df94492267b3783e3411cbKarl Rosaenimport android.widget.*;
34d322c437fe48dc03f0df94492267b3783e3411cbKarl Rosaenimport android.util.Log;
35d322c437fe48dc03f0df94492267b3783e3411cbKarl Rosaenimport android.media.AudioManager;
3682d6c68b396323789e52c407b18ee4a7eab11a24Daniel Sandlerimport android.provider.Settings;
3736931ac9b3cc2e8f60f730c51e715744b5c4f6c0Jim Miller
38bd998018ed028c1922d3cf14aeabe24ff1818761Jim Millerimport java.io.File;
391f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
401f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project/**
411f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project * The screen within {@link LockPatternKeyguardView} that shows general
421f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project * information about the device depending on its state, and how to get
431f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project * past it, as applicable.
441f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project */
456b05d58018c2806459c121e507c005639b74aee9Jim Millerclass LockScreen extends LinearLayout implements KeyguardScreen {
46d322c437fe48dc03f0df94492267b3783e3411cbKarl Rosaen
47bd998018ed028c1922d3cf14aeabe24ff1818761Jim Miller    private static final boolean DBG = false;
48bd998018ed028c1922d3cf14aeabe24ff1818761Jim Miller    private static final String TAG = "LockScreen";
49bd998018ed028c1922d3cf14aeabe24ff1818761Jim Miller    private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key";
506b05d58018c2806459c121e507c005639b74aee9Jim Miller    private static final int WAIT_FOR_ANIMATION_TIMEOUT = 0;
516b05d58018c2806459c121e507c005639b74aee9Jim Miller    private static final int STAY_ON_WHILE_GRABBED_TIMEOUT = 30000;
52d322c437fe48dc03f0df94492267b3783e3411cbKarl Rosaen
538b886fab5496b0b1f5193f21855220176deddc37Jim Miller    private LockPatternUtils mLockPatternUtils;
548b886fab5496b0b1f5193f21855220176deddc37Jim Miller    private KeyguardUpdateMonitor mUpdateMonitor;
558b886fab5496b0b1f5193f21855220176deddc37Jim Miller    private KeyguardScreenCallback mCallback;
561f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
575475906f53e2d79807548932dfabbf9945143740Jim Miller    // current configuration state of keyboard and display
585475906f53e2d79807548932dfabbf9945143740Jim Miller    private int mKeyboardHidden;
595475906f53e2d79807548932dfabbf9945143740Jim Miller    private int mCreationOrientation;
605475906f53e2d79807548932dfabbf9945143740Jim Miller
61d322c437fe48dc03f0df94492267b3783e3411cbKarl Rosaen    private boolean mSilentMode;
62ec3fc0a6415319a5f4f292b8f3d95eb400b33fbcKarl Rosaen    private AudioManager mAudioManager;
63bd998018ed028c1922d3cf14aeabe24ff1818761Jim Miller    private boolean mEnableMenuKeyInLockScreen;
64d322c437fe48dc03f0df94492267b3783e3411cbKarl Rosaen
656b05d58018c2806459c121e507c005639b74aee9Jim Miller    private KeyguardStatusViewManager mStatusViewManager;
661c8d207201150c29ac92c424e1320c715a64b5bcJim Miller    private UnlockWidgetCommonMethods mUnlockWidgetMethods;
671c8d207201150c29ac92c424e1320c715a64b5bcJim Miller    private View mUnlockWidget;
681c8d207201150c29ac92c424e1320c715a64b5bcJim Miller
691c8d207201150c29ac92c424e1320c715a64b5bcJim Miller    private interface UnlockWidgetCommonMethods {
701c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        // Update resources based on phone state
711c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        public void updateResources();
721c8d207201150c29ac92c424e1320c715a64b5bcJim Miller
731c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        // Get the view associated with this widget
741c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        public View getView();
753060421045d4d9e411797f91bb509824b03e33fbJim Miller
761c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        // Reset the view
771c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        public void reset(boolean animate);
781c8d207201150c29ac92c424e1320c715a64b5bcJim Miller
791c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        // Animate the widget if it supports ping()
801c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        public void ping();
811c8d207201150c29ac92c424e1320c715a64b5bcJim Miller    }
821c8d207201150c29ac92c424e1320c715a64b5bcJim Miller
831c8d207201150c29ac92c424e1320c715a64b5bcJim Miller    class SlidingTabMethods implements SlidingTab.OnTriggerListener, UnlockWidgetCommonMethods {
841c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        private final SlidingTab mSlidingTab;
851c8d207201150c29ac92c424e1320c715a64b5bcJim Miller
861c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        SlidingTabMethods(SlidingTab slidingTab) {
871c8d207201150c29ac92c424e1320c715a64b5bcJim Miller            mSlidingTab = slidingTab;
881c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        }
891c8d207201150c29ac92c424e1320c715a64b5bcJim Miller
901c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        public void updateResources() {
913060421045d4d9e411797f91bb509824b03e33fbJim Miller            boolean vibe = mSilentMode
923060421045d4d9e411797f91bb509824b03e33fbJim Miller                && (mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE);
933060421045d4d9e411797f91bb509824b03e33fbJim Miller
943060421045d4d9e411797f91bb509824b03e33fbJim Miller            mSlidingTab.setRightTabResources(
953060421045d4d9e411797f91bb509824b03e33fbJim Miller                    mSilentMode ? ( vibe ? R.drawable.ic_jog_dial_vibrate_on
963060421045d4d9e411797f91bb509824b03e33fbJim Miller                                         : R.drawable.ic_jog_dial_sound_off )
973060421045d4d9e411797f91bb509824b03e33fbJim Miller                                : R.drawable.ic_jog_dial_sound_on,
983060421045d4d9e411797f91bb509824b03e33fbJim Miller                    mSilentMode ? R.drawable.jog_tab_target_yellow
993060421045d4d9e411797f91bb509824b03e33fbJim Miller                                : R.drawable.jog_tab_target_gray,
1003060421045d4d9e411797f91bb509824b03e33fbJim Miller                    mSilentMode ? R.drawable.jog_tab_bar_right_sound_on
1013060421045d4d9e411797f91bb509824b03e33fbJim Miller                                : R.drawable.jog_tab_bar_right_sound_off,
1023060421045d4d9e411797f91bb509824b03e33fbJim Miller                    mSilentMode ? R.drawable.jog_tab_right_sound_on
1033060421045d4d9e411797f91bb509824b03e33fbJim Miller                                : R.drawable.jog_tab_right_sound_off);
1043060421045d4d9e411797f91bb509824b03e33fbJim Miller        }
1053060421045d4d9e411797f91bb509824b03e33fbJim Miller
1063060421045d4d9e411797f91bb509824b03e33fbJim Miller        /** {@inheritDoc} */
1073060421045d4d9e411797f91bb509824b03e33fbJim Miller        public void onTrigger(View v, int whichHandle) {
1083060421045d4d9e411797f91bb509824b03e33fbJim Miller            if (whichHandle == SlidingTab.OnTriggerListener.LEFT_HANDLE) {
1093060421045d4d9e411797f91bb509824b03e33fbJim Miller                mCallback.goToUnlockScreen();
1103060421045d4d9e411797f91bb509824b03e33fbJim Miller            } else if (whichHandle == SlidingTab.OnTriggerListener.RIGHT_HANDLE) {
111b505074e8273887fbcd1e933738a42e770085fb8Jim Miller                toggleRingMode();
1123060421045d4d9e411797f91bb509824b03e33fbJim Miller                mCallback.pokeWakelock();
1133060421045d4d9e411797f91bb509824b03e33fbJim Miller            }
1143060421045d4d9e411797f91bb509824b03e33fbJim Miller        }
1153060421045d4d9e411797f91bb509824b03e33fbJim Miller
1163060421045d4d9e411797f91bb509824b03e33fbJim Miller        /** {@inheritDoc} */
1173060421045d4d9e411797f91bb509824b03e33fbJim Miller        public void onGrabbedStateChange(View v, int grabbedState) {
1183060421045d4d9e411797f91bb509824b03e33fbJim Miller            if (grabbedState == SlidingTab.OnTriggerListener.RIGHT_HANDLE) {
1193060421045d4d9e411797f91bb509824b03e33fbJim Miller                mSilentMode = isSilentMode();
1203060421045d4d9e411797f91bb509824b03e33fbJim Miller                mSlidingTab.setRightHintText(mSilentMode ? R.string.lockscreen_sound_on_label
1213060421045d4d9e411797f91bb509824b03e33fbJim Miller                        : R.string.lockscreen_sound_off_label);
1223060421045d4d9e411797f91bb509824b03e33fbJim Miller            }
1234d396052deb54399cbadbeb8abd873df6f3af342Jeff Brown            // Don't poke the wake lock when returning to a state where the handle is
1244d396052deb54399cbadbeb8abd873df6f3af342Jeff Brown            // not grabbed since that can happen when the system (instead of the user)
1254d396052deb54399cbadbeb8abd873df6f3af342Jeff Brown            // cancels the grab.
1264d396052deb54399cbadbeb8abd873df6f3af342Jeff Brown            if (grabbedState != SlidingTab.OnTriggerListener.NO_HANDLE) {
1274d396052deb54399cbadbeb8abd873df6f3af342Jeff Brown                mCallback.pokeWakelock();
1284d396052deb54399cbadbeb8abd873df6f3af342Jeff Brown            }
1293060421045d4d9e411797f91bb509824b03e33fbJim Miller        }
1301c8d207201150c29ac92c424e1320c715a64b5bcJim Miller
1311c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        public View getView() {
1321c8d207201150c29ac92c424e1320c715a64b5bcJim Miller            return mSlidingTab;
1331c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        }
1341c8d207201150c29ac92c424e1320c715a64b5bcJim Miller
1351c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        public void reset(boolean animate) {
1361c8d207201150c29ac92c424e1320c715a64b5bcJim Miller            mSlidingTab.reset(animate);
1371c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        }
1381c8d207201150c29ac92c424e1320c715a64b5bcJim Miller
1391c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        public void ping() {
1401c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        }
1413060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
1423060421045d4d9e411797f91bb509824b03e33fbJim Miller
1431c8d207201150c29ac92c424e1320c715a64b5bcJim Miller    class WaveViewMethods implements WaveView.OnTriggerListener, UnlockWidgetCommonMethods {
1441c8d207201150c29ac92c424e1320c715a64b5bcJim Miller
1451c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        private final WaveView mWaveView;
1461c8d207201150c29ac92c424e1320c715a64b5bcJim Miller
1471c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        WaveViewMethods(WaveView waveView) {
1481c8d207201150c29ac92c424e1320c715a64b5bcJim Miller            mWaveView = waveView;
1491c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        }
1503060421045d4d9e411797f91bb509824b03e33fbJim Miller        /** {@inheritDoc} */
1513060421045d4d9e411797f91bb509824b03e33fbJim Miller        public void onTrigger(View v, int whichHandle) {
1523060421045d4d9e411797f91bb509824b03e33fbJim Miller            if (whichHandle == WaveView.OnTriggerListener.CENTER_HANDLE) {
153b505074e8273887fbcd1e933738a42e770085fb8Jim Miller                requestUnlockScreen();
1543060421045d4d9e411797f91bb509824b03e33fbJim Miller            }
1553060421045d4d9e411797f91bb509824b03e33fbJim Miller        }
1563060421045d4d9e411797f91bb509824b03e33fbJim Miller
1573060421045d4d9e411797f91bb509824b03e33fbJim Miller        /** {@inheritDoc} */
1583060421045d4d9e411797f91bb509824b03e33fbJim Miller        public void onGrabbedStateChange(View v, int grabbedState) {
1594d396052deb54399cbadbeb8abd873df6f3af342Jeff Brown            // Don't poke the wake lock when returning to a state where the handle is
1604d396052deb54399cbadbeb8abd873df6f3af342Jeff Brown            // not grabbed since that can happen when the system (instead of the user)
1614d396052deb54399cbadbeb8abd873df6f3af342Jeff Brown            // cancels the grab.
1624139b5505c1e07c56900aa72dd91a01e6b740f5fJim Miller            if (grabbedState == WaveView.OnTriggerListener.CENTER_HANDLE) {
1634139b5505c1e07c56900aa72dd91a01e6b740f5fJim Miller                mCallback.pokeWakelock(STAY_ON_WHILE_GRABBED_TIMEOUT);
1644139b5505c1e07c56900aa72dd91a01e6b740f5fJim Miller            }
1653060421045d4d9e411797f91bb509824b03e33fbJim Miller        }
1661c8d207201150c29ac92c424e1320c715a64b5bcJim Miller
1671c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        public void updateResources() {
1681c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        }
1691c8d207201150c29ac92c424e1320c715a64b5bcJim Miller
1701c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        public View getView() {
1711c8d207201150c29ac92c424e1320c715a64b5bcJim Miller            return mWaveView;
1721c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        }
1731c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        public void reset(boolean animate) {
1741c8d207201150c29ac92c424e1320c715a64b5bcJim Miller            mWaveView.reset();
1751c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        }
1761c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        public void ping() {
1771c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        }
1783060421045d4d9e411797f91bb509824b03e33fbJim Miller    }
1793060421045d4d9e411797f91bb509824b03e33fbJim Miller
1801c8d207201150c29ac92c424e1320c715a64b5bcJim Miller    class MultiWaveViewMethods implements MultiWaveView.OnTriggerListener,
1811c8d207201150c29ac92c424e1320c715a64b5bcJim Miller            UnlockWidgetCommonMethods {
1821c8d207201150c29ac92c424e1320c715a64b5bcJim Miller
1831c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        private final MultiWaveView mMultiWaveView;
1841c8d207201150c29ac92c424e1320c715a64b5bcJim Miller
1851c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        MultiWaveViewMethods(MultiWaveView multiWaveView) {
1861c8d207201150c29ac92c424e1320c715a64b5bcJim Miller            mMultiWaveView = multiWaveView;
1871c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        }
1881c8d207201150c29ac92c424e1320c715a64b5bcJim Miller
1891c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        public void updateResources() {
1901c8d207201150c29ac92c424e1320c715a64b5bcJim Miller            mMultiWaveView.setTargetResources(mSilentMode ? R.array.lockscreen_targets_when_silent
1911c8d207201150c29ac92c424e1320c715a64b5bcJim Miller                    : R.array.lockscreen_targets_when_soundon);
1921c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        }
1931c8d207201150c29ac92c424e1320c715a64b5bcJim Miller
194b505074e8273887fbcd1e933738a42e770085fb8Jim Miller        public void onGrabbed(View v, int handle) {
195b505074e8273887fbcd1e933738a42e770085fb8Jim Miller
196b505074e8273887fbcd1e933738a42e770085fb8Jim Miller        }
1971c8d207201150c29ac92c424e1320c715a64b5bcJim Miller
198b505074e8273887fbcd1e933738a42e770085fb8Jim Miller        public void onReleased(View v, int handle) {
199b505074e8273887fbcd1e933738a42e770085fb8Jim Miller
200b505074e8273887fbcd1e933738a42e770085fb8Jim Miller        }
2011c8d207201150c29ac92c424e1320c715a64b5bcJim Miller
202b505074e8273887fbcd1e933738a42e770085fb8Jim Miller        public void onTrigger(View v, int target) {
203b505074e8273887fbcd1e933738a42e770085fb8Jim Miller            if (target == 0) { // TODO: Use resources to determine which handle was used
204b505074e8273887fbcd1e933738a42e770085fb8Jim Miller                mCallback.goToUnlockScreen();
205b505074e8273887fbcd1e933738a42e770085fb8Jim Miller            } else if (target == 2) {
206b505074e8273887fbcd1e933738a42e770085fb8Jim Miller                toggleRingMode();
2071c8d207201150c29ac92c424e1320c715a64b5bcJim Miller                mUnlockWidgetMethods.updateResources();
208b505074e8273887fbcd1e933738a42e770085fb8Jim Miller                mCallback.pokeWakelock();
209b505074e8273887fbcd1e933738a42e770085fb8Jim Miller            }
210b505074e8273887fbcd1e933738a42e770085fb8Jim Miller        }
211b505074e8273887fbcd1e933738a42e770085fb8Jim Miller
212b505074e8273887fbcd1e933738a42e770085fb8Jim Miller        public void onGrabbedStateChange(View v, int handle) {
213b505074e8273887fbcd1e933738a42e770085fb8Jim Miller            // Don't poke the wake lock when returning to a state where the handle is
214b505074e8273887fbcd1e933738a42e770085fb8Jim Miller            // not grabbed since that can happen when the system (instead of the user)
215b505074e8273887fbcd1e933738a42e770085fb8Jim Miller            // cancels the grab.
216b505074e8273887fbcd1e933738a42e770085fb8Jim Miller            if (handle != MultiWaveView.OnTriggerListener.NO_HANDLE) {
217b505074e8273887fbcd1e933738a42e770085fb8Jim Miller                mCallback.pokeWakelock();
218b505074e8273887fbcd1e933738a42e770085fb8Jim Miller            }
219b505074e8273887fbcd1e933738a42e770085fb8Jim Miller        }
2201c8d207201150c29ac92c424e1320c715a64b5bcJim Miller
2211c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        public View getView() {
2221c8d207201150c29ac92c424e1320c715a64b5bcJim Miller            return mMultiWaveView;
2231c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        }
2241c8d207201150c29ac92c424e1320c715a64b5bcJim Miller
2251c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        public void reset(boolean animate) {
2261c8d207201150c29ac92c424e1320c715a64b5bcJim Miller            mMultiWaveView.reset(animate);
2271c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        }
2281c8d207201150c29ac92c424e1320c715a64b5bcJim Miller
2291c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        public void ping() {
2301c8d207201150c29ac92c424e1320c715a64b5bcJim Miller            mMultiWaveView.ping();
2311c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        }
232b505074e8273887fbcd1e933738a42e770085fb8Jim Miller    }
233b505074e8273887fbcd1e933738a42e770085fb8Jim Miller
234b505074e8273887fbcd1e933738a42e770085fb8Jim Miller    private void requestUnlockScreen() {
235b505074e8273887fbcd1e933738a42e770085fb8Jim Miller        // Delay hiding lock screen long enough for animation to finish
236b505074e8273887fbcd1e933738a42e770085fb8Jim Miller        postDelayed(new Runnable() {
237b505074e8273887fbcd1e933738a42e770085fb8Jim Miller            public void run() {
238b505074e8273887fbcd1e933738a42e770085fb8Jim Miller                mCallback.goToUnlockScreen();
239b505074e8273887fbcd1e933738a42e770085fb8Jim Miller            }
240b505074e8273887fbcd1e933738a42e770085fb8Jim Miller        }, WAIT_FOR_ANIMATION_TIMEOUT);
241b505074e8273887fbcd1e933738a42e770085fb8Jim Miller    }
242b505074e8273887fbcd1e933738a42e770085fb8Jim Miller
243b505074e8273887fbcd1e933738a42e770085fb8Jim Miller    private void toggleRingMode() {
244b505074e8273887fbcd1e933738a42e770085fb8Jim Miller        // toggle silent mode
245b505074e8273887fbcd1e933738a42e770085fb8Jim Miller        mSilentMode = !mSilentMode;
246b505074e8273887fbcd1e933738a42e770085fb8Jim Miller        if (mSilentMode) {
247b505074e8273887fbcd1e933738a42e770085fb8Jim Miller            final boolean vibe = (Settings.System.getInt(
2486b05d58018c2806459c121e507c005639b74aee9Jim Miller                mContext.getContentResolver(),
249b505074e8273887fbcd1e933738a42e770085fb8Jim Miller                Settings.System.VIBRATE_IN_SILENT, 1) == 1);
250b505074e8273887fbcd1e933738a42e770085fb8Jim Miller
251b505074e8273887fbcd1e933738a42e770085fb8Jim Miller            mAudioManager.setRingerMode(vibe
252b505074e8273887fbcd1e933738a42e770085fb8Jim Miller                ? AudioManager.RINGER_MODE_VIBRATE
253b505074e8273887fbcd1e933738a42e770085fb8Jim Miller                : AudioManager.RINGER_MODE_SILENT);
254b505074e8273887fbcd1e933738a42e770085fb8Jim Miller        } else {
255b505074e8273887fbcd1e933738a42e770085fb8Jim Miller            mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
256b505074e8273887fbcd1e933738a42e770085fb8Jim Miller        }
257b505074e8273887fbcd1e933738a42e770085fb8Jim Miller    }
258b505074e8273887fbcd1e933738a42e770085fb8Jim Miller
259bd998018ed028c1922d3cf14aeabe24ff1818761Jim Miller    /**
260bd998018ed028c1922d3cf14aeabe24ff1818761Jim Miller     * In general, we enable unlocking the insecure key guard with the menu key. However, there are
261bd998018ed028c1922d3cf14aeabe24ff1818761Jim Miller     * some cases where we wish to disable it, notably when the menu button placement or technology
262bd998018ed028c1922d3cf14aeabe24ff1818761Jim Miller     * is prone to false positives.
263bd998018ed028c1922d3cf14aeabe24ff1818761Jim Miller     *
264bd998018ed028c1922d3cf14aeabe24ff1818761Jim Miller     * @return true if the menu key should be enabled
265bd998018ed028c1922d3cf14aeabe24ff1818761Jim Miller     */
266bd998018ed028c1922d3cf14aeabe24ff1818761Jim Miller    private boolean shouldEnableMenuKey() {
267bd998018ed028c1922d3cf14aeabe24ff1818761Jim Miller        final Resources res = getResources();
268bd998018ed028c1922d3cf14aeabe24ff1818761Jim Miller        final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen);
2693b4fcbc9f13bab6a2e9e5c37cc5e18fec7341c04Brett Chabot        final boolean isTestHarness = ActivityManager.isRunningInTestHarness();
270bd998018ed028c1922d3cf14aeabe24ff1818761Jim Miller        final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists();
2713b4fcbc9f13bab6a2e9e5c37cc5e18fec7341c04Brett Chabot        return !configDisabled || isTestHarness || fileOverride;
272bd998018ed028c1922d3cf14aeabe24ff1818761Jim Miller    }
2731f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
2741f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    /**
2751f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project     * @param context Used to setup the view.
2765475906f53e2d79807548932dfabbf9945143740Jim Miller     * @param configuration The current configuration. Used to use when selecting layout, etc.
2771f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project     * @param lockPatternUtils Used to know the state of the lock pattern settings.
2781f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project     * @param updateMonitor Used to register for updates on various keyguard related
2791f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project     *    state, and query the initial state at setup.
2801f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project     * @param callback Used to communicate back to the host keyguard view.
2811f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project     */
2825475906f53e2d79807548932dfabbf9945143740Jim Miller    LockScreen(Context context, Configuration configuration, LockPatternUtils lockPatternUtils,
2831f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project            KeyguardUpdateMonitor updateMonitor,
2841f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project            KeyguardScreenCallback callback) {
2851f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        super(context);
2861f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        mLockPatternUtils = lockPatternUtils;
2871f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        mUpdateMonitor = updateMonitor;
2881f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        mCallback = callback;
2891f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
290bd998018ed028c1922d3cf14aeabe24ff1818761Jim Miller        mEnableMenuKeyInLockScreen = shouldEnableMenuKey();
2918ed9870f54eb06e32f3639cd4f2852876bfc1666Jim Miller
2925475906f53e2d79807548932dfabbf9945143740Jim Miller        mCreationOrientation = configuration.orientation;
2935475906f53e2d79807548932dfabbf9945143740Jim Miller
2945475906f53e2d79807548932dfabbf9945143740Jim Miller        mKeyboardHidden = configuration.hardKeyboardHidden;
29580be841eafe3b7b9f8dba820ba3201843717e610Karl Rosaen
29675787398fa5db9add16f3d3bc298198ed2c6671fDianne Hackborn        if (LockPatternKeyguardView.DEBUG_CONFIGURATION) {
29775787398fa5db9add16f3d3bc298198ed2c6671fDianne Hackborn            Log.v(TAG, "***** CREATING LOCK SCREEN", new RuntimeException());
29875787398fa5db9add16f3d3bc298198ed2c6671fDianne Hackborn            Log.v(TAG, "Cur orient=" + mCreationOrientation
29975787398fa5db9add16f3d3bc298198ed2c6671fDianne Hackborn                    + " res orient=" + context.getResources().getConfiguration().orientation);
30075787398fa5db9add16f3d3bc298198ed2c6671fDianne Hackborn        }
301368de81b71af00628b60558a52c7df53e1cd1e96Daniel Sandler
3021f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        final LayoutInflater inflater = LayoutInflater.from(context);
3035475906f53e2d79807548932dfabbf9945143740Jim Miller        if (DBG) Log.v(TAG, "Creation orientation = " + mCreationOrientation);
3045475906f53e2d79807548932dfabbf9945143740Jim Miller        if (mCreationOrientation != Configuration.ORIENTATION_LANDSCAPE) {
30580080e54ef571a5109563d4bfc4619197961f51aJim Miller            inflater.inflate(R.layout.keyguard_screen_tab_unlock, this, true);
30680be841eafe3b7b9f8dba820ba3201843717e610Karl Rosaen        } else {
30780080e54ef571a5109563d4bfc4619197961f51aJim Miller            inflater.inflate(R.layout.keyguard_screen_tab_unlock_land, this, true);
30880be841eafe3b7b9f8dba820ba3201843717e610Karl Rosaen        }
3091f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
3106b05d58018c2806459c121e507c005639b74aee9Jim Miller        mStatusViewManager = new KeyguardStatusViewManager(this, mUpdateMonitor, mLockPatternUtils,
3116b05d58018c2806459c121e507c005639b74aee9Jim Miller                mCallback);
3123bb65ee33b3001fe4100fe0779ad214d6898a465Daniel Sandler
3136b05d58018c2806459c121e507c005639b74aee9Jim Miller        // LockScreen doesn't show the emergency call button by default
3146b05d58018c2806459c121e507c005639b74aee9Jim Miller        mStatusViewManager.hideEmergencyCallButton();
3151f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
3161f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        setFocusable(true);
3171f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        setFocusableInTouchMode(true);
3181f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
3191f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
3206b05d58018c2806459c121e507c005639b74aee9Jim Miller        mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
321c119f1299b63c224df5e7fa9c197f394eee890caJim Miller        mSilentMode = isSilentMode();
322d322c437fe48dc03f0df94492267b3783e3411cbKarl Rosaen
3231c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        mUnlockWidget = findViewById(R.id.unlock_widget);
3241c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        if (mUnlockWidget instanceof SlidingTab) {
3251c8d207201150c29ac92c424e1320c715a64b5bcJim Miller            SlidingTab slidingTabView = (SlidingTab) mUnlockWidget;
3261c8d207201150c29ac92c424e1320c715a64b5bcJim Miller            slidingTabView.setHoldAfterTrigger(true, false);
3271c8d207201150c29ac92c424e1320c715a64b5bcJim Miller            slidingTabView.setLeftHintText(R.string.lockscreen_unlock_label);
3281c8d207201150c29ac92c424e1320c715a64b5bcJim Miller            slidingTabView.setLeftTabResources(
3293060421045d4d9e411797f91bb509824b03e33fbJim Miller                    R.drawable.ic_jog_dial_unlock,
3303060421045d4d9e411797f91bb509824b03e33fbJim Miller                    R.drawable.jog_tab_target_green,
3313060421045d4d9e411797f91bb509824b03e33fbJim Miller                    R.drawable.jog_tab_bar_left_unlock,
3323060421045d4d9e411797f91bb509824b03e33fbJim Miller                    R.drawable.jog_tab_left_unlock);
3331c8d207201150c29ac92c424e1320c715a64b5bcJim Miller            SlidingTabMethods slidingTabMethods = new SlidingTabMethods(slidingTabView);
3341c8d207201150c29ac92c424e1320c715a64b5bcJim Miller            slidingTabView.setOnTriggerListener(slidingTabMethods);
3351c8d207201150c29ac92c424e1320c715a64b5bcJim Miller            mUnlockWidgetMethods = slidingTabMethods;
3361c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        } else if (mUnlockWidget instanceof WaveView) {
3371c8d207201150c29ac92c424e1320c715a64b5bcJim Miller            WaveView waveView = (WaveView) mUnlockWidget;
3381c8d207201150c29ac92c424e1320c715a64b5bcJim Miller            WaveViewMethods waveViewMethods = new WaveViewMethods(waveView);
3391c8d207201150c29ac92c424e1320c715a64b5bcJim Miller            waveView.setOnTriggerListener(waveViewMethods);
3401c8d207201150c29ac92c424e1320c715a64b5bcJim Miller            mUnlockWidgetMethods = waveViewMethods;
3411c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        } else if (mUnlockWidget instanceof MultiWaveView) {
3421c8d207201150c29ac92c424e1320c715a64b5bcJim Miller            MultiWaveView multiWaveView = (MultiWaveView) mUnlockWidget;
3431c8d207201150c29ac92c424e1320c715a64b5bcJim Miller            MultiWaveViewMethods multiWaveViewMethods = new MultiWaveViewMethods(multiWaveView);
3441c8d207201150c29ac92c424e1320c715a64b5bcJim Miller            multiWaveView.setOnTriggerListener(multiWaveViewMethods);
3451c8d207201150c29ac92c424e1320c715a64b5bcJim Miller            mUnlockWidgetMethods = multiWaveViewMethods;
3463060421045d4d9e411797f91bb509824b03e33fbJim Miller        } else {
3471c8d207201150c29ac92c424e1320c715a64b5bcJim Miller            throw new IllegalStateException("Unrecognized unlock widget: " + mUnlockWidget);
3483060421045d4d9e411797f91bb509824b03e33fbJim Miller        }
349c119f1299b63c224df5e7fa9c197f394eee890caJim Miller
3501c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        // Update widget with initial ring state
3511c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        mUnlockWidgetMethods.updateResources();
3521c8d207201150c29ac92c424e1320c715a64b5bcJim Miller
3531c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        if (DBG) Log.v(TAG, "*** LockScreen accel is "
3541c8d207201150c29ac92c424e1320c715a64b5bcJim Miller                + (mUnlockWidget.isHardwareAccelerated() ? "on":"off"));
355a35d753adda055582e319bc98f30f11b138b2936Karl Rosaen    }
356a35d753adda055582e319bc98f30f11b138b2936Karl Rosaen
357c119f1299b63c224df5e7fa9c197f394eee890caJim Miller    private boolean isSilentMode() {
35882d6c68b396323789e52c407b18ee4a7eab11a24Daniel Sandler        return mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL;
359c119f1299b63c224df5e7fa9c197f394eee890caJim Miller    }
360c119f1299b63c224df5e7fa9c197f394eee890caJim Miller
3611f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    @Override
3621f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    public boolean onKeyDown(int keyCode, KeyEvent event) {
363bd998018ed028c1922d3cf14aeabe24ff1818761Jim Miller        if (keyCode == KeyEvent.KEYCODE_MENU && mEnableMenuKeyInLockScreen) {
3641f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project            mCallback.goToUnlockScreen();
3651f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        }
3661f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        return false;
3671f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    }
3681f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
36975787398fa5db9add16f3d3bc298198ed2c6671fDianne Hackborn    void updateConfiguration() {
37075787398fa5db9add16f3d3bc298198ed2c6671fDianne Hackborn        Configuration newConfig = getResources().getConfiguration();
3715475906f53e2d79807548932dfabbf9945143740Jim Miller        if (newConfig.orientation != mCreationOrientation) {
3725475906f53e2d79807548932dfabbf9945143740Jim Miller            mCallback.recreateMe(newConfig);
3735475906f53e2d79807548932dfabbf9945143740Jim Miller        } else if (newConfig.hardKeyboardHidden != mKeyboardHidden) {
3745475906f53e2d79807548932dfabbf9945143740Jim Miller            mKeyboardHidden = newConfig.hardKeyboardHidden;
3755475906f53e2d79807548932dfabbf9945143740Jim Miller            final boolean isKeyboardOpen = mKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO;
3765475906f53e2d79807548932dfabbf9945143740Jim Miller            if (mUpdateMonitor.isKeyguardBypassEnabled() && isKeyboardOpen) {
3775475906f53e2d79807548932dfabbf9945143740Jim Miller                mCallback.goToUnlockScreen();
3785475906f53e2d79807548932dfabbf9945143740Jim Miller            }
3791f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        }
3801f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    }
381368de81b71af00628b60558a52c7df53e1cd1e96Daniel Sandler
38275787398fa5db9add16f3d3bc298198ed2c6671fDianne Hackborn    @Override
38375787398fa5db9add16f3d3bc298198ed2c6671fDianne Hackborn    protected void onAttachedToWindow() {
38475787398fa5db9add16f3d3bc298198ed2c6671fDianne Hackborn        super.onAttachedToWindow();
38575787398fa5db9add16f3d3bc298198ed2c6671fDianne Hackborn        if (LockPatternKeyguardView.DEBUG_CONFIGURATION) {
38675787398fa5db9add16f3d3bc298198ed2c6671fDianne Hackborn            Log.v(TAG, "***** LOCK ATTACHED TO WINDOW");
38775787398fa5db9add16f3d3bc298198ed2c6671fDianne Hackborn            Log.v(TAG, "Cur orient=" + mCreationOrientation
38875787398fa5db9add16f3d3bc298198ed2c6671fDianne Hackborn                    + ", new config=" + getResources().getConfiguration());
38975787398fa5db9add16f3d3bc298198ed2c6671fDianne Hackborn        }
39075787398fa5db9add16f3d3bc298198ed2c6671fDianne Hackborn        updateConfiguration();
39175787398fa5db9add16f3d3bc298198ed2c6671fDianne Hackborn    }
39275787398fa5db9add16f3d3bc298198ed2c6671fDianne Hackborn
39375787398fa5db9add16f3d3bc298198ed2c6671fDianne Hackborn    /** {@inheritDoc} */
39475787398fa5db9add16f3d3bc298198ed2c6671fDianne Hackborn    @Override
39575787398fa5db9add16f3d3bc298198ed2c6671fDianne Hackborn    protected void onConfigurationChanged(Configuration newConfig) {
39675787398fa5db9add16f3d3bc298198ed2c6671fDianne Hackborn        super.onConfigurationChanged(newConfig);
39775787398fa5db9add16f3d3bc298198ed2c6671fDianne Hackborn        if (LockPatternKeyguardView.DEBUG_CONFIGURATION) {
39875787398fa5db9add16f3d3bc298198ed2c6671fDianne Hackborn            Log.w(TAG, "***** LOCK CONFIG CHANGING", new RuntimeException());
39975787398fa5db9add16f3d3bc298198ed2c6671fDianne Hackborn            Log.v(TAG, "Cur orient=" + mCreationOrientation
40075787398fa5db9add16f3d3bc298198ed2c6671fDianne Hackborn                    + ", new config=" + newConfig);
40175787398fa5db9add16f3d3bc298198ed2c6671fDianne Hackborn        }
40275787398fa5db9add16f3d3bc298198ed2c6671fDianne Hackborn        updateConfiguration();
40375787398fa5db9add16f3d3bc298198ed2c6671fDianne Hackborn    }
4041f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
4051f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    /** {@inheritDoc} */
4061f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    public boolean needsInput() {
4071f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        return false;
4081f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    }
40947088bbbef61e3bd8d2930f4a2b72884129b5bd5Jim Miller
4101f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    /** {@inheritDoc} */
4111f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    public void onPause() {
4126b05d58018c2806459c121e507c005639b74aee9Jim Miller        mStatusViewManager.onPause();
4131c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        mUnlockWidgetMethods.reset(false);
4141f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    }
4151f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
4161f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    /** {@inheritDoc} */
4171f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    public void onResume() {
4186b05d58018c2806459c121e507c005639b74aee9Jim Miller        mStatusViewManager.onResume();
4191c8d207201150c29ac92c424e1320c715a64b5bcJim Miller        mUnlockWidgetMethods.ping();
4201f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    }
4211f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
4221f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    /** {@inheritDoc} */
4231f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    public void cleanUp() {
4248b886fab5496b0b1f5193f21855220176deddc37Jim Miller        mUpdateMonitor.removeCallback(this); // this must be first
4258b886fab5496b0b1f5193f21855220176deddc37Jim Miller        mLockPatternUtils = null;
4268b886fab5496b0b1f5193f21855220176deddc37Jim Miller        mUpdateMonitor = null;
4278b886fab5496b0b1f5193f21855220176deddc37Jim Miller        mCallback = null;
4281f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    }
42947088bbbef61e3bd8d2930f4a2b72884129b5bd5Jim Miller
43047088bbbef61e3bd8d2930f4a2b72884129b5bd5Jim Miller    /** {@inheritDoc} */
43147088bbbef61e3bd8d2930f4a2b72884129b5bd5Jim Miller    public void onRingerModeChanged(int state) {
43282d6c68b396323789e52c407b18ee4a7eab11a24Daniel Sandler        boolean silent = AudioManager.RINGER_MODE_NORMAL != state;
43347088bbbef61e3bd8d2930f4a2b72884129b5bd5Jim Miller        if (silent != mSilentMode) {
43447088bbbef61e3bd8d2930f4a2b72884129b5bd5Jim Miller            mSilentMode = silent;
4351c8d207201150c29ac92c424e1320c715a64b5bcJim Miller            mUnlockWidgetMethods.updateResources();
43647088bbbef61e3bd8d2930f4a2b72884129b5bd5Jim Miller        }
43747088bbbef61e3bd8d2930f4a2b72884129b5bd5Jim Miller    }
438c23024d32779b170dde32a50fbdd945ce521b874Jim Miller
439c23024d32779b170dde32a50fbdd945ce521b874Jim Miller    public void onPhoneStateChanged(String newState) {
440c23024d32779b170dde32a50fbdd945ce521b874Jim Miller    }
4411f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project}
442