blob: 1bae9b83e9daf7ae8cbbed4215b2330e9155ccd9 [file] [log] [blame]
Jim Millerdcb3d842012-08-23 19:18:12 -07001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Jim Miller5ecd8112013-01-09 18:50:26 -080017package com.android.keyguard;
18
Jim Miller4d20ed32013-10-19 01:00:16 +000019import com.android.internal.widget.LockPatternUtils;
20import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
21import com.android.keyguard.KeyguardUpdateMonitor.DisplayClientState;
22
Jim Miller258341c2012-08-30 16:50:10 -070023import android.app.Activity;
Jim Miller95b005c2012-08-29 16:43:32 -070024import android.app.ActivityManager;
Jim Millerdcb3d842012-08-23 19:18:12 -070025import android.app.ActivityOptions;
Jim Miller258341c2012-08-30 16:50:10 -070026import android.app.AlertDialog;
Jim Miller4eeb4f62012-11-08 00:04:29 -080027import android.app.SearchManager;
Jim Miller258341c2012-08-30 16:50:10 -070028import android.app.admin.DevicePolicyManager;
Jim Millerdcb3d842012-08-23 19:18:12 -070029import android.appwidget.AppWidgetHost;
30import android.appwidget.AppWidgetHostView;
31import android.appwidget.AppWidgetManager;
32import android.appwidget.AppWidgetProviderInfo;
Michael Jurkafc753c02012-10-30 18:30:52 -070033import android.content.ComponentName;
Jim Millerdcb3d842012-08-23 19:18:12 -070034import android.content.Context;
35import android.content.Intent;
36import android.content.IntentSender;
Jim Millera75a8832013-02-07 16:53:32 -080037import android.content.pm.PackageManager.NameNotFoundException;
Adam Cohen66b9fb1662012-09-05 16:23:58 -070038import android.content.pm.UserInfo;
Jim Miller95b005c2012-08-29 16:43:32 -070039import android.content.res.Resources;
Jim Millerdcb3d842012-08-23 19:18:12 -070040import android.graphics.Canvas;
Jim Miller57375342012-09-09 15:20:31 -070041import android.graphics.Rect;
Jim Miller8f09fd22013-03-14 19:04:28 -070042import android.media.RemoteControlClient;
Jim Millerf229e4d2012-09-12 20:32:50 -070043import android.os.Looper;
Jim Miller223ce5c2012-10-05 19:13:23 -070044import android.os.Parcel;
45import android.os.Parcelable;
John Spurlockdbe24b72012-11-01 13:01:05 -040046import android.os.SystemClock;
Jim Miller4eeb4f62012-11-08 00:04:29 -080047import android.os.UserHandle;
Adam Cohen66b9fb1662012-09-05 16:23:58 -070048import android.os.UserManager;
Michael Jurkafff56142012-11-28 16:51:00 -080049import android.provider.Settings;
Jim Millerdcb3d842012-08-23 19:18:12 -070050import android.util.AttributeSet;
51import android.util.Log;
Jim Miller258341c2012-08-30 16:50:10 -070052import android.util.Slog;
Adam Cohen66b9fb1662012-09-05 16:23:58 -070053import android.view.LayoutInflater;
Jim Miller57375342012-09-09 15:20:31 -070054import android.view.MotionEvent;
Jim Millerdcb3d842012-08-23 19:18:12 -070055import android.view.View;
Jim Miller258341c2012-08-30 16:50:10 -070056import android.view.WindowManager;
Jim Millerdcb3d842012-08-23 19:18:12 -070057import android.widget.RemoteViews.OnClickHandler;
58
Jim Miller95b005c2012-08-29 16:43:32 -070059import java.io.File;
Chet Haase7fc27ea2013-10-01 15:34:22 -070060import java.lang.ref.WeakReference;
Adam Cohen66b9fb1662012-09-05 16:23:58 -070061import java.util.List;
Jim Millerdcb3d842012-08-23 19:18:12 -070062
63public class KeyguardHostView extends KeyguardViewBase {
Jim Miller51117262012-11-04 17:58:09 -080064 private static final String TAG = "KeyguardHostView";
Sandeep Siddharthaeec83dc2013-09-04 14:59:59 -070065
Jim Miller4894a012013-04-03 15:23:55 -070066 // Transport control states.
Jim Miller8f09fd22013-03-14 19:04:28 -070067 static final int TRANSPORT_GONE = 0;
68 static final int TRANSPORT_INVISIBLE = 1;
69 static final int TRANSPORT_VISIBLE = 2;
70
71 private int mTransportState = TRANSPORT_GONE;
Jim Millerff2aa0b2012-09-06 19:03:52 -070072
Jim Millerdcb3d842012-08-23 19:18:12 -070073 // Use this to debug all of keyguard
Jim Millera71984f2012-10-24 22:08:49 -070074 public static boolean DEBUG = KeyguardViewMediator.DEBUG;
Jim Miller8f09fd22013-03-14 19:04:28 -070075 public static boolean DEBUGXPORT = true; // debug music transport control
Jim Millerdcb3d842012-08-23 19:18:12 -070076
Michael Jurka192d6d42012-11-07 01:09:38 -080077 // Found in KeyguardAppWidgetPickActivity.java
Jim Millerdcb3d842012-08-23 19:18:12 -070078 static final int APPWIDGET_HOST_ID = 0x4B455947;
Jim Millerdcb3d842012-08-23 19:18:12 -070079
Michael Jurkaeb963f02012-11-08 00:32:29 -080080 private final int MAX_WIDGETS = 5;
81
Jim Millerdcb3d842012-08-23 19:18:12 -070082 private AppWidgetHost mAppWidgetHost;
Michael Jurka67a871d2012-11-01 18:26:01 -070083 private AppWidgetManager mAppWidgetManager;
Jim Millerf2dfc352012-08-29 18:42:21 -070084 private KeyguardWidgetPager mAppWidgetContainer;
Adam Cohen6fb841f2012-10-24 13:15:38 -070085 private KeyguardSecurityViewFlipper mSecurityViewContainer;
Adam Cohen0a8d3262012-10-03 13:50:55 -070086 private KeyguardSelectorView mKeyguardSelectorView;
Jim Miller4e81bd42012-10-01 20:21:02 -070087 private KeyguardTransportControlView mTransportControl;
Jim Millerdcb3d842012-08-23 19:18:12 -070088 private boolean mIsVerifyUnlockOnly;
Jim Miller258341c2012-08-30 16:50:10 -070089 private boolean mEnableFallback; // TODO: This should get the value from KeyguardPatternView
Jim Miller63f9b812012-10-15 15:58:01 -070090 private SecurityMode mCurrentSecuritySelection = SecurityMode.Invalid;
Michael Jurka76017ca2012-11-06 16:21:09 -080091 private int mAppWidgetToShow;
Jim Millerdcb3d842012-08-23 19:18:12 -070092
John Spurlock34c4fe52012-11-07 10:12:29 -050093 protected OnDismissAction mDismissAction;
Jim Millerdcb3d842012-08-23 19:18:12 -070094
95 protected int mFailedAttempts;
96 private LockPatternUtils mLockPatternUtils;
97
98 private KeyguardSecurityModel mSecurityModel;
Jim Millerd6523da2012-10-21 16:47:02 -070099 private KeyguardViewStateManager mViewStateManager;
Jim Millerdcb3d842012-08-23 19:18:12 -0700100
Jim Miller57375342012-09-09 15:20:31 -0700101 private Rect mTempRect = new Rect();
Jim Millerff2aa0b2012-09-06 19:03:52 -0700102
Jim Miller51117262012-11-04 17:58:09 -0800103 private int mDisabledFeatures;
104
105 private boolean mCameraDisabled;
106
107 private boolean mSafeModeEnabled;
108
Michael Jurkafff56142012-11-28 16:51:00 -0800109 private boolean mUserSetupCompleted;
Chris Wrenf41c61b2012-11-29 15:19:54 -0500110
Jim Millera75a8832013-02-07 16:53:32 -0800111 // User for whom this host view was created. Final because we should never change the
112 // id without reconstructing an instance of KeyguardHostView. See note below...
113 private final int mUserId;
Michael Jurkafff56142012-11-28 16:51:00 -0800114
Chris Wrenf41c61b2012-11-29 15:19:54 -0500115 private KeyguardMultiUserSelectorView mKeyguardMultiUserSelectorView;
116
Jim Miller8f09fd22013-03-14 19:04:28 -0700117 protected int mClientGeneration;
Jim Miller57375342012-09-09 15:20:31 -0700118
Jim Millere51cf7ae2013-06-25 18:31:56 -0700119 protected boolean mShowSecurityWhenReturn;
120
John Spurlock256ae672013-09-26 12:14:33 -0400121 private final Rect mInsets = new Rect();
122
Chet Haase7fc27ea2013-10-01 15:34:22 -0700123 private MyOnClickHandler mOnClickHandler = new MyOnClickHandler(this);
124
Jim Miller9ccf1232013-10-10 22:23:07 -0700125 private Runnable mPostBootCompletedRunnable;
126
Adam Cohen24b351a2012-09-14 15:02:27 -0700127 /*package*/ interface UserSwitcherCallback {
128 void hideSecurityView(int duration);
129 void showSecurityView();
Adam Cohen0a8d3262012-10-03 13:50:55 -0700130 void showUnlockHint();
Jim Miller19a52672012-10-23 19:52:04 -0700131 void userActivity();
Adam Cohen24b351a2012-09-14 15:02:27 -0700132 }
133
Adam Powellf8895242013-09-30 16:16:24 -0700134 interface TransportControlCallback {
135 void userActivity();
136 }
137
John Spurlock14adfe42012-11-08 10:29:26 -0500138 /*package*/ interface OnDismissAction {
139 /* returns true if the dismiss should be deferred */
140 boolean onDismiss();
141 }
142
Jim Millerdcb3d842012-08-23 19:18:12 -0700143 public KeyguardHostView(Context context) {
144 this(context, null);
145 }
146
147 public KeyguardHostView(Context context, AttributeSet attrs) {
148 super(context, attrs);
Jim Miller4894a012013-04-03 15:23:55 -0700149
150 if (DEBUG) Log.e(TAG, "KeyguardHostView()");
151
Jim Miller000464a2012-09-04 16:45:06 -0700152 mLockPatternUtils = new LockPatternUtils(context);
Jim Millera75a8832013-02-07 16:53:32 -0800153
154 // Note: This depends on KeyguardHostView getting reconstructed every time the
155 // user switches, since mUserId will be used for the entire session.
156 // Once created, keyguard should *never* re-use this instance with another user.
157 // In other words, mUserId should never change - hence it's marked final.
Amith Yamasanic566b432012-11-30 15:26:21 -0800158 mUserId = mLockPatternUtils.getCurrentUser();
Jim Millera75a8832013-02-07 16:53:32 -0800159
Jim Miller105bedd2013-02-27 21:35:18 -0800160 DevicePolicyManager dpm =
161 (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
162 if (dpm != null) {
163 mDisabledFeatures = getDisabledFeatures(dpm);
164 mCameraDisabled = dpm.getCameraDisabled(null);
165 }
166
167 mSafeModeEnabled = LockPatternUtils.isSafeModeEnabled();
168
169 // These need to be created with the user context...
Jim Millera75a8832013-02-07 16:53:32 -0800170 Context userContext = null;
171 try {
172 final String packageName = "system";
173 userContext = mContext.createPackageContextAsUser(packageName, 0,
174 new UserHandle(mUserId));
175
176 } catch (NameNotFoundException e) {
177 e.printStackTrace();
178 // This should never happen, but it's better to have no widgets than to crash.
179 userContext = context;
180 }
181
Jim Millera75a8832013-02-07 16:53:32 -0800182 mAppWidgetHost = new AppWidgetHost(userContext, APPWIDGET_HOST_ID, mOnClickHandler,
183 Looper.myLooper());
Jim Miller105bedd2013-02-27 21:35:18 -0800184
Jim Millera75a8832013-02-07 16:53:32 -0800185 mAppWidgetManager = AppWidgetManager.getInstance(userContext);
186
Jim Millerf229e4d2012-09-12 20:32:50 -0700187 mSecurityModel = new KeyguardSecurityModel(context);
Jim Miller95b005c2012-08-29 16:43:32 -0700188
Adam Cohend6f89602012-11-06 11:46:25 -0800189 mViewStateManager = new KeyguardViewStateManager(this);
Jim Miller51117262012-11-04 17:58:09 -0800190
Michael Jurkafff56142012-11-28 16:51:00 -0800191 mUserSetupCompleted = Settings.Secure.getIntForUser(mContext.getContentResolver(),
192 Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
Jim Miller51117262012-11-04 17:58:09 -0800193
Jim Miller8f09fd22013-03-14 19:04:28 -0700194 // Ensure we have the current state *before* we call showAppropriateWidgetPage()
195 getInitialTransportState();
196
Jim Miller51117262012-11-04 17:58:09 -0800197 if (mSafeModeEnabled) {
198 Log.v(TAG, "Keyguard widgets disabled by safe mode");
199 }
200 if ((mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL) != 0) {
201 Log.v(TAG, "Keyguard widgets disabled by DPM");
202 }
203 if ((mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0) {
204 Log.v(TAG, "Keyguard secure camera disabled by DPM");
205 }
Jim Millerdcb3d842012-08-23 19:18:12 -0700206 }
207
Jim Miller138f25d2013-09-25 13:46:58 -0700208 public void announceCurrentSecurityMethod() {
209 View v = (View) getSecurityView(mCurrentSecuritySelection);
210 if (v != null) {
211 v.announceForAccessibility(v.getContentDescription());
212 }
213 }
214
Jim Miller8f09fd22013-03-14 19:04:28 -0700215 private void getInitialTransportState() {
216 DisplayClientState dcs = KeyguardUpdateMonitor.getInstance(mContext)
217 .getCachedDisplayClientState();
218 mTransportState = (dcs.clearing ? TRANSPORT_GONE :
219 (isMusicPlaying(dcs.playbackState) ? TRANSPORT_VISIBLE : TRANSPORT_INVISIBLE));
Jim Miller4894a012013-04-03 15:23:55 -0700220
Jim Miller81190be2013-11-05 18:17:59 -0800221 if (DEBUGXPORT) Log.v(TAG, "Initial transport state: "
Jim Millerdfb57cd2013-05-30 16:43:53 -0700222 + mTransportState + ", pbstate=" + dcs.playbackState);
Jim Miller8f09fd22013-03-14 19:04:28 -0700223 }
224
Michael Jurka75b5cfb2012-11-15 18:22:47 -0800225 private void cleanupAppWidgetIds() {
Jim Miller9ccf1232013-10-10 22:23:07 -0700226 if (mSafeModeEnabled || widgetsDisabled()) return;
227
228 // Clean up appWidgetIds that are bound to lockscreen, but not actually used
229 // This is only to clean up after another bug: we used to not call
230 // deleteAppWidgetId when a user manually deleted a widget in keyguard. This code
231 // shouldn't have to run more than once per user. AppWidgetProviders rely on callbacks
232 // that are triggered by deleteAppWidgetId, which is why we're doing this
233 int[] appWidgetIdsInKeyguardSettings = mLockPatternUtils.getAppWidgets();
234 int[] appWidgetIdsBoundToHost = mAppWidgetHost.getAppWidgetIds();
235 for (int i = 0; i < appWidgetIdsBoundToHost.length; i++) {
236 int appWidgetId = appWidgetIdsBoundToHost[i];
237 if (!contains(appWidgetIdsInKeyguardSettings, appWidgetId)) {
238 Log.d(TAG, "Found a appWidgetId that's not being used by keyguard, deleting id "
239 + appWidgetId);
240 mAppWidgetHost.deleteAppWidgetId(appWidgetId);
Michael Jurka75b5cfb2012-11-15 18:22:47 -0800241 }
242 }
243 }
244
245 private static boolean contains(int[] array, int target) {
246 for (int value : array) {
247 if (value == target) {
248 return true;
249 }
250 }
251 return false;
252 }
253
Adam Cohenefb3ffb2012-11-06 16:55:32 -0800254 private KeyguardUpdateMonitorCallback mUpdateMonitorCallbacks =
255 new KeyguardUpdateMonitorCallback() {
256 @Override
257 public void onBootCompleted() {
Jim Miller9ccf1232013-10-10 22:23:07 -0700258 if (mPostBootCompletedRunnable != null) {
259 mPostBootCompletedRunnable.run();
260 mPostBootCompletedRunnable = null;
Michael Jurka545043e2012-11-21 14:02:34 -0800261 }
Adam Cohenefb3ffb2012-11-06 16:55:32 -0800262 }
Chris Wrenf41c61b2012-11-29 15:19:54 -0500263 @Override
264 public void onUserSwitchComplete(int userId) {
265 if (mKeyguardMultiUserSelectorView != null) {
266 mKeyguardMultiUserSelectorView.finalizeActiveUserView(true);
267 }
268 }
Jim Miller8f09fd22013-03-14 19:04:28 -0700269 @Override
270 void onMusicClientIdChanged(
271 int clientGeneration, boolean clearing, android.app.PendingIntent intent) {
272 // Set transport state to invisible until we know music is playing (below)
273 if (DEBUGXPORT && (mClientGeneration != clientGeneration || clearing)) {
274 Log.v(TAG, (clearing ? "hide" : "show") + " transport, gen:" + clientGeneration);
275 }
276 mClientGeneration = clientGeneration;
Jim Millerdfb57cd2013-05-30 16:43:53 -0700277 final int newState = (clearing ? TRANSPORT_GONE
278 : (mTransportState == TRANSPORT_VISIBLE ?
279 TRANSPORT_VISIBLE : TRANSPORT_INVISIBLE));
280 if (newState != mTransportState) {
281 mTransportState = newState;
282 if (DEBUGXPORT) Log.v(TAG, "update widget: transport state changed");
Jim Miller4d20ed32013-10-19 01:00:16 +0000283 KeyguardHostView.this.post(mSwitchPageRunnable);
Jim Millerdfb57cd2013-05-30 16:43:53 -0700284 }
Jim Miller8f09fd22013-03-14 19:04:28 -0700285 }
286 @Override
287 public void onMusicPlaybackStateChanged(int playbackState, long eventTime) {
Jim Miller8f09fd22013-03-14 19:04:28 -0700288 if (DEBUGXPORT) Log.v(TAG, "music state changed: " + playbackState);
289 if (mTransportState != TRANSPORT_GONE) {
Jim Millerdfb57cd2013-05-30 16:43:53 -0700290 final int newState = (isMusicPlaying(playbackState) ?
Jim Miller8f09fd22013-03-14 19:04:28 -0700291 TRANSPORT_VISIBLE : TRANSPORT_INVISIBLE);
Jim Millerdfb57cd2013-05-30 16:43:53 -0700292 if (newState != mTransportState) {
293 mTransportState = newState;
294 if (DEBUGXPORT) Log.v(TAG, "update widget: play state changed");
Jim Miller4d20ed32013-10-19 01:00:16 +0000295 KeyguardHostView.this.post(mSwitchPageRunnable);
Jim Millerdfb57cd2013-05-30 16:43:53 -0700296 }
Jim Miller8f09fd22013-03-14 19:04:28 -0700297 }
Jim Miller8f09fd22013-03-14 19:04:28 -0700298 }
Adam Cohenefb3ffb2012-11-06 16:55:32 -0800299 };
300
Jim Miller8f09fd22013-03-14 19:04:28 -0700301 private static final boolean isMusicPlaying(int playbackState) {
302 // This should agree with the list in AudioService.isPlaystateActive()
303 switch (playbackState) {
304 case RemoteControlClient.PLAYSTATE_PLAYING:
305 case RemoteControlClient.PLAYSTATE_BUFFERING:
306 case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
307 case RemoteControlClient.PLAYSTATE_REWINDING:
308 case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
309 case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
310 return true;
311 default:
312 return false;
313 }
314 }
315
Jim Miller2cacda52012-11-07 22:40:20 -0800316 private SlidingChallengeLayout mSlidingChallengeLayout;
John Spurlock257f2832013-09-21 18:41:53 -0400317 private MultiPaneChallengeLayout mMultiPaneChallengeLayout;
Jim Miller2cacda52012-11-07 22:40:20 -0800318
Jim Millerdcb3d842012-08-23 19:18:12 -0700319 @Override
Jim Millerd2b82f72012-09-18 20:52:55 -0700320 public boolean onTouchEvent(MotionEvent ev) {
321 boolean result = super.onTouchEvent(ev);
Jim Miller57375342012-09-09 15:20:31 -0700322 mTempRect.set(0, 0, 0, 0);
323 offsetRectIntoDescendantCoords(mSecurityViewContainer, mTempRect);
324 ev.offsetLocation(mTempRect.left, mTempRect.top);
325 result = mSecurityViewContainer.dispatchTouchEvent(ev) || result;
326 ev.offsetLocation(-mTempRect.left, -mTempRect.top);
327 return result;
328 }
329
330 @Override
Jim Millerdcb3d842012-08-23 19:18:12 -0700331 protected void dispatchDraw(Canvas canvas) {
332 super.dispatchDraw(canvas);
Craig Mautner7def1db2012-09-28 10:27:56 -0700333 if (mViewMediatorCallback != null) {
334 mViewMediatorCallback.keyguardDoneDrawing();
335 }
Jim Millerdcb3d842012-08-23 19:18:12 -0700336 }
337
Jim Millerff2aa0b2012-09-06 19:03:52 -0700338 private int getWidgetPosition(int id) {
Jim Miller982d21b2013-05-09 14:43:16 -0700339 final KeyguardWidgetPager appWidgetContainer = mAppWidgetContainer;
340 final int children = appWidgetContainer.getChildCount();
Jim Millerff2aa0b2012-09-06 19:03:52 -0700341 for (int i = 0; i < children; i++) {
Jim Miller982d21b2013-05-09 14:43:16 -0700342 final View content = appWidgetContainer.getWidgetPageAt(i).getContent();
343 if (content != null && content.getId() == id) {
Jim Millerff2aa0b2012-09-06 19:03:52 -0700344 return i;
Jim Miller982d21b2013-05-09 14:43:16 -0700345 } else if (content == null) {
346 // Attempt to track down bug #8886916
347 Log.w(TAG, "*** Null content at " + "i=" + i + ",id=" + id + ",N=" + children);
Jim Millerff2aa0b2012-09-06 19:03:52 -0700348 }
349 }
350 return -1;
351 }
352
Jim Millerdcb3d842012-08-23 19:18:12 -0700353 @Override
354 protected void onFinishInflate() {
Jim Millerd6523da2012-10-21 16:47:02 -0700355 // Grab instances of and make any necessary changes to the main layouts. Create
356 // view state manager and wire up necessary listeners / callbacks.
Winson Chungf3b9ec82012-11-01 14:48:51 -0700357 View deleteDropTarget = findViewById(R.id.keyguard_widget_pager_delete_target);
Jim Millerf2dfc352012-08-29 18:42:21 -0700358 mAppWidgetContainer = (KeyguardWidgetPager) findViewById(R.id.app_widget_container);
Jim Miller838906b2012-10-19 18:41:25 -0700359 mAppWidgetContainer.setVisibility(VISIBLE);
360 mAppWidgetContainer.setCallbacks(mWidgetCallbacks);
Winson Chungf3b9ec82012-11-01 14:48:51 -0700361 mAppWidgetContainer.setDeleteDropTarget(deleteDropTarget);
Jim Millerd6523da2012-10-21 16:47:02 -0700362 mAppWidgetContainer.setMinScale(0.5f);
363
Jim Miller2cacda52012-11-07 22:40:20 -0800364 mSlidingChallengeLayout = (SlidingChallengeLayout) findViewById(R.id.sliding_layout);
365 if (mSlidingChallengeLayout != null) {
366 mSlidingChallengeLayout.setOnChallengeScrolledListener(mViewStateManager);
Jim Miller19a52672012-10-23 19:52:04 -0700367 }
Jim Millerd6523da2012-10-21 16:47:02 -0700368 mAppWidgetContainer.setViewStateManager(mViewStateManager);
Michael Jurka1254f2f2012-10-25 11:44:31 -0700369 mAppWidgetContainer.setLockPatternUtils(mLockPatternUtils);
Jim Millerd6523da2012-10-21 16:47:02 -0700370
John Spurlock257f2832013-09-21 18:41:53 -0400371 mMultiPaneChallengeLayout =
372 (MultiPaneChallengeLayout) findViewById(R.id.multi_pane_challenge);
Jim Miller2cacda52012-11-07 22:40:20 -0800373 ChallengeLayout challenge = mSlidingChallengeLayout != null ? mSlidingChallengeLayout :
John Spurlock257f2832013-09-21 18:41:53 -0400374 mMultiPaneChallengeLayout;
Winson Chung48275d22012-11-05 10:56:31 -0800375 challenge.setOnBouncerStateChangedListener(mViewStateManager);
Winson Chung70c2f872012-11-07 21:47:12 -0800376 mAppWidgetContainer.setBouncerAnimationDuration(challenge.getBouncerAnimationDuration());
Jim Millerd6523da2012-10-21 16:47:02 -0700377 mViewStateManager.setPagedView(mAppWidgetContainer);
Winson Chung48275d22012-11-05 10:56:31 -0800378 mViewStateManager.setChallengeLayout(challenge);
Adam Cohen6fb841f2012-10-24 13:15:38 -0700379 mSecurityViewContainer = (KeyguardSecurityViewFlipper) findViewById(R.id.view_flipper);
Adam Cohen0a8d3262012-10-03 13:50:55 -0700380 mKeyguardSelectorView = (KeyguardSelectorView) findViewById(R.id.keyguard_selector_view);
Adam Cohen6fb841f2012-10-24 13:15:38 -0700381 mViewStateManager.setSecurityViewContainer(mSecurityViewContainer);
Jim Millerff2aa0b2012-09-06 19:03:52 -0700382
John Spurlock03eca852013-03-14 14:21:04 -0400383 setBackButtonEnabled(false);
Jim Miller68c24892012-10-14 05:04:00 -0700384
Jim Miller9ccf1232013-10-10 22:23:07 -0700385 if (KeyguardUpdateMonitor.getInstance(mContext).hasBootCompleted()) {
386 updateAndAddWidgets();
387 } else {
388 // We can't add widgets until after boot completes because AppWidgetHost may try
389 // to contact the providers. Do it later.
390 mPostBootCompletedRunnable = new Runnable() {
391 @Override
392 public void run() {
393 updateAndAddWidgets();
394 }
395 };
Michael Jurkaeb963f02012-11-08 00:32:29 -0800396 }
Jim Miller9ccf1232013-10-10 22:23:07 -0700397
398 showPrimarySecurityScreen(false);
399 updateSecurityViews();
400 enableUserSelectorIfNecessary();
401 }
402
403 private void updateAndAddWidgets() {
404 cleanupAppWidgetIds();
405 addDefaultWidgets();
406 addWidgetsFromSettings();
407 maybeEnableAddButton();
Jim Miller51117262012-11-04 17:58:09 -0800408 checkAppWidgetConsistency();
Jim Miller5547b552013-10-07 19:20:56 -0700409
410 // Don't let the user drag the challenge down if widgets are disabled.
411 if (mSlidingChallengeLayout != null) {
412 mSlidingChallengeLayout.setEnableChallengeDragging(!widgetsDisabled());
413 }
414
Jim Miller9ccf1232013-10-10 22:23:07 -0700415 // Select the appropriate page
Jim Miller51117262012-11-04 17:58:09 -0800416 mSwitchPageRunnable.run();
Jim Miller9ccf1232013-10-10 22:23:07 -0700417
Adam Cohen45adaa72012-11-02 22:00:57 -0700418 // This needs to be called after the pages are all added.
419 mViewStateManager.showUsabilityHints();
Jim Miller9ccf1232013-10-10 22:23:07 -0700420 }
Adam Cohen45adaa72012-11-02 22:00:57 -0700421
Jim Miller9ccf1232013-10-10 22:23:07 -0700422 private void maybeEnableAddButton() {
423 if (!shouldEnableAddWidget()) {
424 mAppWidgetContainer.setAddWidgetEnabled(false);
425 }
Jim Millere46efc02012-09-07 16:43:51 -0700426 }
Jim Millerdcb3d842012-08-23 19:18:12 -0700427
John Spurlock03eca852013-03-14 14:21:04 -0400428 private void setBackButtonEnabled(boolean enabled) {
429 if (mContext instanceof Activity) return; // always enabled in activity mode
430 setSystemUiVisibility(enabled ?
431 getSystemUiVisibility() & ~View.STATUS_BAR_DISABLE_BACK :
432 getSystemUiVisibility() | View.STATUS_BAR_DISABLE_BACK);
433 }
434
Michael Jurkafff56142012-11-28 16:51:00 -0800435 private boolean shouldEnableAddWidget() {
436 return numWidgets() < MAX_WIDGETS && mUserSetupCompleted;
437 }
438
Jim Miller51117262012-11-04 17:58:09 -0800439 private int getDisabledFeatures(DevicePolicyManager dpm) {
440 int disabledFeatures = DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE;
441 if (dpm != null) {
442 final int currentUser = mLockPatternUtils.getCurrentUser();
443 disabledFeatures = dpm.getKeyguardDisabledFeatures(null, currentUser);
444 }
445 return disabledFeatures;
446 }
447
Jim Millerf45bb402013-08-20 18:58:32 -0700448 private boolean widgetsDisabled() {
Jim Miller461b3452013-09-29 14:00:01 -0700449 boolean disabledByLowRamDevice = ActivityManager.isLowRamDeviceStatic();
Jim Millerf45bb402013-08-20 18:58:32 -0700450 boolean disabledByDpm =
451 (mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL) != 0;
452 boolean disabledByUser = !mLockPatternUtils.getWidgetsEnabled();
Jim Miller461b3452013-09-29 14:00:01 -0700453 return disabledByLowRamDevice || disabledByDpm || disabledByUser;
Jim Miller51117262012-11-04 17:58:09 -0800454 }
455
456 private boolean cameraDisabledByDpm() {
457 return mCameraDisabled
458 || (mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0;
459 }
460
Jim Millere46efc02012-09-07 16:43:51 -0700461 private void updateSecurityViews() {
462 int children = mSecurityViewContainer.getChildCount();
463 for (int i = 0; i < children; i++) {
464 updateSecurityView(mSecurityViewContainer.getChildAt(i));
465 }
466 }
Jim Millerdcb3d842012-08-23 19:18:12 -0700467
Jim Millere46efc02012-09-07 16:43:51 -0700468 private void updateSecurityView(View view) {
469 if (view instanceof KeyguardSecurityView) {
470 KeyguardSecurityView ksv = (KeyguardSecurityView) view;
471 ksv.setKeyguardCallback(mCallback);
472 ksv.setLockPatternUtils(mLockPatternUtils);
Chris Wrenc0ae9e62012-11-05 13:16:31 -0500473 if (mViewStateManager.isBouncing()) {
474 ksv.showBouncer(0);
475 } else {
476 ksv.hideBouncer(0);
477 }
Jim Millere46efc02012-09-07 16:43:51 -0700478 } else {
479 Log.w(TAG, "View " + view + " is not a KeyguardSecurityView");
Jim Millerdcb3d842012-08-23 19:18:12 -0700480 }
Jim Millerdcb3d842012-08-23 19:18:12 -0700481 }
482
483 void setLockPatternUtils(LockPatternUtils utils) {
484 mSecurityModel.setLockPatternUtils(utils);
485 mLockPatternUtils = utils;
Jim Millere46efc02012-09-07 16:43:51 -0700486 updateSecurityViews();
Jim Millerdcb3d842012-08-23 19:18:12 -0700487 }
488
489 @Override
490 protected void onAttachedToWindow() {
491 super.onAttachedToWindow();
Jim Millera75a8832013-02-07 16:53:32 -0800492 mAppWidgetHost.startListening();
Adam Cohenefb3ffb2012-11-06 16:55:32 -0800493 KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallbacks);
Jim Miller7221d3a2012-10-05 14:34:47 -0700494 }
495
Jim Millerdcb3d842012-08-23 19:18:12 -0700496 @Override
497 protected void onDetachedFromWindow() {
498 super.onDetachedFromWindow();
Jim Millera75a8832013-02-07 16:53:32 -0800499 mAppWidgetHost.stopListening();
Adam Cohenefb3ffb2012-11-06 16:55:32 -0800500 KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateMonitorCallbacks);
Jim Millerdcb3d842012-08-23 19:18:12 -0700501 }
502
Jim Millerd6523da2012-10-21 16:47:02 -0700503 void addWidget(AppWidgetHostView view, int pageIndex) {
504 mAppWidgetContainer.addWidget(view, pageIndex);
Jim Millerdcb3d842012-08-23 19:18:12 -0700505 }
506
Jim Miller838906b2012-10-19 18:41:25 -0700507 private KeyguardWidgetPager.Callbacks mWidgetCallbacks
508 = new KeyguardWidgetPager.Callbacks() {
Jeff Brownc7505bc2012-10-05 21:58:15 -0700509 @Override
510 public void userActivity() {
Adam Cohen08c83ef2012-11-08 00:25:47 -0800511 KeyguardHostView.this.userActivity();
Jeff Brownc7505bc2012-10-05 21:58:15 -0700512 }
513
514 @Override
515 public void onUserActivityTimeoutChanged() {
Adam Cohen08c83ef2012-11-08 00:25:47 -0800516 KeyguardHostView.this.onUserActivityTimeoutChanged();
Jeff Brownc7505bc2012-10-05 21:58:15 -0700517 }
Michael Jurkaeb963f02012-11-08 00:32:29 -0800518
519 @Override
Winson Chung40f82112012-11-08 11:54:55 -0800520 public void onAddView(View v) {
Michael Jurkafff56142012-11-28 16:51:00 -0800521 if (!shouldEnableAddWidget()) {
Winson Chung4752e7d2012-11-20 17:06:04 -0800522 mAppWidgetContainer.setAddWidgetEnabled(false);
Winson Chung40f82112012-11-08 11:54:55 -0800523 }
Winson Chung4752e7d2012-11-20 17:06:04 -0800524 }
Winson Chung40f82112012-11-08 11:54:55 -0800525
526 @Override
Michael Jurka75b5cfb2012-11-15 18:22:47 -0800527 public void onRemoveView(View v, boolean deletePermanently) {
Michael Jurka75b5cfb2012-11-15 18:22:47 -0800528 if (deletePermanently) {
529 final int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId();
530 if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID &&
531 appWidgetId != LockPatternUtils.ID_DEFAULT_STATUS_WIDGET) {
532 mAppWidgetHost.deleteAppWidgetId(appWidgetId);
533 }
534 }
Michael Jurkaeb963f02012-11-08 00:32:29 -0800535 }
Winson Chung4752e7d2012-11-20 17:06:04 -0800536
537 @Override
538 public void onRemoveViewAnimationCompleted() {
Michael Jurkafff56142012-11-28 16:51:00 -0800539 if (shouldEnableAddWidget()) {
Winson Chung4752e7d2012-11-20 17:06:04 -0800540 mAppWidgetContainer.setAddWidgetEnabled(true);
541 }
542 }
Jeff Brownc7505bc2012-10-05 21:58:15 -0700543 };
544
Chris Wrenf41c61b2012-11-29 15:19:54 -0500545 public void initializeSwitchingUserState(boolean switching) {
546 if (!switching && mKeyguardMultiUserSelectorView != null) {
547 mKeyguardMultiUserSelectorView.finalizeActiveUserView(false);
548 }
549 }
550
Adam Cohen08c83ef2012-11-08 00:25:47 -0800551 public void userActivity() {
552 if (mViewMediatorCallback != null) {
553 mViewMediatorCallback.userActivity();
554 }
555 }
556
557 public void onUserActivityTimeoutChanged() {
558 if (mViewMediatorCallback != null) {
559 mViewMediatorCallback.onUserActivityTimeoutChanged();
560 }
561 }
562
Jeff Brownc7505bc2012-10-05 21:58:15 -0700563 @Override
564 public long getUserActivityTimeout() {
565 // Currently only considering user activity timeouts needed by widgets.
566 // Could also take into account longer timeouts for certain security views.
Jim Miller838906b2012-10-19 18:41:25 -0700567 if (mAppWidgetContainer != null) {
568 return mAppWidgetContainer.getUserActivityTimeout();
Jeff Brownc7505bc2012-10-05 21:58:15 -0700569 }
570 return -1;
571 }
572
Jim Millerdcb3d842012-08-23 19:18:12 -0700573 private KeyguardSecurityCallback mCallback = new KeyguardSecurityCallback() {
574
575 public void userActivity(long timeout) {
Craig Mautner7def1db2012-09-28 10:27:56 -0700576 if (mViewMediatorCallback != null) {
Jeff Brown3dc524b2012-09-30 19:49:11 -0700577 mViewMediatorCallback.userActivity(timeout);
Craig Mautner7def1db2012-09-28 10:27:56 -0700578 }
Jim Millerdcb3d842012-08-23 19:18:12 -0700579 }
580
581 public void dismiss(boolean authenticated) {
582 showNextSecurityScreenOrFinish(authenticated);
583 }
584
585 public boolean isVerifyUnlockOnly() {
Jim Miller258341c2012-08-30 16:50:10 -0700586 return mIsVerifyUnlockOnly;
Jim Millerdcb3d842012-08-23 19:18:12 -0700587 }
588
589 public void reportSuccessfulUnlockAttempt() {
Jim Miller258341c2012-08-30 16:50:10 -0700590 KeyguardUpdateMonitor.getInstance(mContext).clearFailedUnlockAttempts();
Jim Miller76415062012-09-24 18:38:08 -0700591 mLockPatternUtils.reportSuccessfulPasswordAttempt();
Jim Millerdcb3d842012-08-23 19:18:12 -0700592 }
593
594 public void reportFailedUnlockAttempt() {
Jim Miller76415062012-09-24 18:38:08 -0700595 if (mCurrentSecuritySelection == SecurityMode.Biometric) {
596 KeyguardUpdateMonitor.getInstance(mContext).reportFailedBiometricUnlockAttempt();
597 } else {
598 KeyguardHostView.this.reportFailedUnlockAttempt();
599 }
Jim Millerdcb3d842012-08-23 19:18:12 -0700600 }
601
602 public int getFailedAttempts() {
Jim Miller258341c2012-08-30 16:50:10 -0700603 return KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts();
Jim Millerdcb3d842012-08-23 19:18:12 -0700604 }
605
Jim Miller258341c2012-08-30 16:50:10 -0700606 @Override
607 public void showBackupSecurity() {
Jim Miller0ff7f012012-10-11 20:40:01 -0700608 KeyguardHostView.this.showBackupSecurityScreen();
Jim Millerdcb3d842012-08-23 19:18:12 -0700609 }
610
Jim Miller5f75aa12012-08-29 15:10:34 -0700611 @Override
John Spurlock34c4fe52012-11-07 10:12:29 -0500612 public void setOnDismissAction(OnDismissAction action) {
613 KeyguardHostView.this.setOnDismissAction(action);
Jim Miller5f75aa12012-08-29 15:10:34 -0700614 }
615
Jim Millerdcb3d842012-08-23 19:18:12 -0700616 };
617
Jim Miller258341c2012-08-30 16:50:10 -0700618 private void showDialog(String title, String message) {
619 final AlertDialog dialog = new AlertDialog.Builder(mContext)
620 .setTitle(title)
621 .setMessage(message)
Jim Miller5ecd8112013-01-09 18:50:26 -0800622 .setNeutralButton(R.string.ok, null)
Jim Miller258341c2012-08-30 16:50:10 -0700623 .create();
624 if (!(mContext instanceof Activity)) {
625 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
626 }
627 dialog.show();
628 }
629
630 private void showTimeoutDialog() {
631 int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;
632 int messageId = 0;
633
634 switch (mSecurityModel.getSecurityMode()) {
635 case Pattern:
636 messageId = R.string.kg_too_many_failed_pattern_attempts_dialog_message;
637 break;
Daniel Sandler69bdee72012-10-23 16:45:50 -0400638 case PIN:
639 messageId = R.string.kg_too_many_failed_pin_attempts_dialog_message;
640 break;
641 case Password:
642 messageId = R.string.kg_too_many_failed_password_attempts_dialog_message;
Jim Miller258341c2012-08-30 16:50:10 -0700643 break;
644 }
645
646 if (messageId != 0) {
647 final String message = mContext.getString(messageId,
648 KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts(),
649 timeoutInSeconds);
650 showDialog(null, message);
651 }
652 }
653
654 private void showAlmostAtWipeDialog(int attempts, int remaining) {
Jim Miller258341c2012-08-30 16:50:10 -0700655 String message = mContext.getString(R.string.kg_failed_attempts_almost_at_wipe,
656 attempts, remaining);
657 showDialog(null, message);
658 }
659
660 private void showWipeDialog(int attempts) {
661 String message = mContext.getString(R.string.kg_failed_attempts_now_wiping, attempts);
662 showDialog(null, message);
663 }
664
665 private void showAlmostAtAccountLoginDialog() {
666 final int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;
667 final int count = LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET
668 - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT;
669 String message = mContext.getString(R.string.kg_failed_attempts_almost_at_login,
670 count, LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT, timeoutInSeconds);
671 showDialog(null, message);
672 }
673
674 private void reportFailedUnlockAttempt() {
675 final KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
676 final int failedAttempts = monitor.getFailedUnlockAttempts() + 1; // +1 for this time
677
678 if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts);
679
680 SecurityMode mode = mSecurityModel.getSecurityMode();
681 final boolean usingPattern = mode == KeyguardSecurityModel.SecurityMode.Pattern;
682
683 final int failedAttemptsBeforeWipe = mLockPatternUtils.getDevicePolicyManager()
Amith Yamasani599dd7c2012-09-14 23:20:08 -0700684 .getMaximumFailedPasswordsForWipe(null, mLockPatternUtils.getCurrentUser());
Jim Miller258341c2012-08-30 16:50:10 -0700685
686 final int failedAttemptWarning = LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET
687 - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT;
688
689 final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0 ?
690 (failedAttemptsBeforeWipe - failedAttempts)
691 : Integer.MAX_VALUE; // because DPM returns 0 if no restriction
692
Jim Miller08b2b6b2012-09-14 19:12:40 -0700693 boolean showTimeout = false;
Jim Miller258341c2012-08-30 16:50:10 -0700694 if (remainingBeforeWipe < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) {
695 // If we reach this code, it means the user has installed a DevicePolicyManager
696 // that requests device wipe after N attempts. Once we get below the grace
697 // period, we'll post this dialog every time as a clear warning until the
698 // bombshell hits and the device is wiped.
699 if (remainingBeforeWipe > 0) {
700 showAlmostAtWipeDialog(failedAttempts, remainingBeforeWipe);
701 } else {
702 // Too many attempts. The device will be wiped shortly.
703 Slog.i(TAG, "Too many unlock attempts; device will be wiped!");
704 showWipeDialog(failedAttempts);
705 }
706 } else {
Jim Miller08b2b6b2012-09-14 19:12:40 -0700707 showTimeout =
Jim Miller258341c2012-08-30 16:50:10 -0700708 (failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) == 0;
709 if (usingPattern && mEnableFallback) {
710 if (failedAttempts == failedAttemptWarning) {
711 showAlmostAtAccountLoginDialog();
712 showTimeout = false; // don't show both dialogs
713 } else if (failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) {
714 mLockPatternUtils.setPermanentlyLocked(true);
Jim Millere46efc02012-09-07 16:43:51 -0700715 showSecurityScreen(SecurityMode.Account);
Jim Miller258341c2012-08-30 16:50:10 -0700716 // don't show timeout dialog because we show account unlock screen next
717 showTimeout = false;
718 }
719 }
Jim Miller258341c2012-08-30 16:50:10 -0700720 }
721 monitor.reportFailedUnlockAttempt();
722 mLockPatternUtils.reportFailedPasswordAttempt();
Jim Miller08b2b6b2012-09-14 19:12:40 -0700723 if (showTimeout) {
724 showTimeoutDialog();
725 }
Jim Miller258341c2012-08-30 16:50:10 -0700726 }
727
728 /**
Jim Miller0ff7f012012-10-11 20:40:01 -0700729 * Shows the primary security screen for the user. This will be either the multi-selector
730 * or the user's security method.
731 * @param turningOff true if the device is being turned off
732 */
733 void showPrimarySecurityScreen(boolean turningOff) {
734 SecurityMode securityMode = mSecurityModel.getSecurityMode();
735 if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")");
Brian Colonna078f5912012-10-31 20:03:18 -0400736 if (!turningOff &&
737 KeyguardUpdateMonitor.getInstance(mContext).isAlternateUnlockEnabled()) {
Jim Miller0ff7f012012-10-11 20:40:01 -0700738 // If we're not turning off, then allow biometric alternate.
739 // We'll reload it when the device comes back on.
740 securityMode = mSecurityModel.getAlternateFor(securityMode);
741 }
742 showSecurityScreen(securityMode);
743 }
Jim Miller68c24892012-10-14 05:04:00 -0700744
Jim Miller0ff7f012012-10-11 20:40:01 -0700745 /**
Jim Miller258341c2012-08-30 16:50:10 -0700746 * Shows the backup security screen for the current security mode. This could be used for
747 * password recovery screens but is currently only used for pattern unlock to show the
748 * account unlock screen and biometric unlock to show the user's normal unlock.
749 */
Jim Miller0ff7f012012-10-11 20:40:01 -0700750 private void showBackupSecurityScreen() {
Danielle Millett61413b52012-10-09 18:07:02 -0400751 if (DEBUG) Log.d(TAG, "showBackupSecurity()");
Jim Miller63f9b812012-10-15 15:58:01 -0700752 SecurityMode backup = mSecurityModel.getBackupSecurityMode(mCurrentSecuritySelection);
753 showSecurityScreen(backup);
Jim Miller258341c2012-08-30 16:50:10 -0700754 }
755
Adam Cohen0a8d3262012-10-03 13:50:55 -0700756 public boolean showNextSecurityScreenIfPresent() {
757 SecurityMode securityMode = mSecurityModel.getSecurityMode();
758 // Allow an alternate, such as biometric unlock
759 securityMode = mSecurityModel.getAlternateFor(securityMode);
760 if (SecurityMode.None == securityMode) {
761 return false;
762 } else {
763 showSecurityScreen(securityMode); // switch to the alternate security view
764 return true;
765 }
766 }
767
Jim Miller258341c2012-08-30 16:50:10 -0700768 private void showNextSecurityScreenOrFinish(boolean authenticated) {
Danielle Millett61413b52012-10-09 18:07:02 -0400769 if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
Jim Millerdcb3d842012-08-23 19:18:12 -0700770 boolean finish = false;
Jim Millere46efc02012-09-07 16:43:51 -0700771 if (SecurityMode.None == mCurrentSecuritySelection) {
Jim Miller258341c2012-08-30 16:50:10 -0700772 SecurityMode securityMode = mSecurityModel.getSecurityMode();
773 // Allow an alternate, such as biometric unlock
Jim Miller000464a2012-09-04 16:45:06 -0700774 securityMode = mSecurityModel.getAlternateFor(securityMode);
Jim Millere46efc02012-09-07 16:43:51 -0700775 if (SecurityMode.None == securityMode) {
Jim Millerdcb3d842012-08-23 19:18:12 -0700776 finish = true; // no security required
777 } else {
Jim Millere46efc02012-09-07 16:43:51 -0700778 showSecurityScreen(securityMode); // switch to the alternate security view
Jim Millerdcb3d842012-08-23 19:18:12 -0700779 }
780 } else if (authenticated) {
Jim Millere46efc02012-09-07 16:43:51 -0700781 switch (mCurrentSecuritySelection) {
782 case Pattern:
783 case Password:
Daniel Sandler69bdee72012-10-23 16:45:50 -0400784 case PIN:
Jim Millere46efc02012-09-07 16:43:51 -0700785 case Account:
786 case Biometric:
Jim Miller4b09dd32012-09-04 14:27:25 -0700787 finish = true;
788 break;
789
Jim Millere46efc02012-09-07 16:43:51 -0700790 case SimPin:
791 case SimPuk:
Jim Miller4b09dd32012-09-04 14:27:25 -0700792 // Shortcut for SIM PIN/PUK to go to directly to user's security screen or home
793 SecurityMode securityMode = mSecurityModel.getSecurityMode();
794 if (securityMode != SecurityMode.None) {
Jim Millere46efc02012-09-07 16:43:51 -0700795 showSecurityScreen(securityMode);
Jim Miller4b09dd32012-09-04 14:27:25 -0700796 } else {
797 finish = true;
798 }
799 break;
800
801 default:
Jim Miller0ff7f012012-10-11 20:40:01 -0700802 Log.v(TAG, "Bad security screen " + mCurrentSecuritySelection + ", fail safe");
803 showPrimarySecurityScreen(false);
Jim Miller4b09dd32012-09-04 14:27:25 -0700804 break;
Jim Millerdcb3d842012-08-23 19:18:12 -0700805 }
806 } else {
Jim Miller0ff7f012012-10-11 20:40:01 -0700807 showPrimarySecurityScreen(false);
Jim Millerdcb3d842012-08-23 19:18:12 -0700808 }
809 if (finish) {
Jim Miller0ff7f012012-10-11 20:40:01 -0700810 // If the alternate unlock was suppressed, it can now be safely
811 // enabled because the user has left keyguard.
812 KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true);
Jim Miller68c24892012-10-14 05:04:00 -0700813
Jim Millerdcb3d842012-08-23 19:18:12 -0700814 // If there's a pending runnable because the user interacted with a widget
815 // and we're leaving keyguard, then run it.
John Spurlock34c4fe52012-11-07 10:12:29 -0500816 boolean deferKeyguardDone = false;
817 if (mDismissAction != null) {
818 deferKeyguardDone = mDismissAction.onDismiss();
819 mDismissAction = null;
Jim Millerdcb3d842012-08-23 19:18:12 -0700820 }
Craig Mautner7def1db2012-09-28 10:27:56 -0700821 if (mViewMediatorCallback != null) {
John Spurlock34c4fe52012-11-07 10:12:29 -0500822 if (deferKeyguardDone) {
823 mViewMediatorCallback.keyguardDonePending();
824 } else {
825 mViewMediatorCallback.keyguardDone(true);
826 }
Craig Mautner7def1db2012-09-28 10:27:56 -0700827 }
Jim Millerb5f3b702012-10-21 19:09:23 -0700828 } else {
829 mViewStateManager.showBouncer(true);
Jim Millerdcb3d842012-08-23 19:18:12 -0700830 }
831 }
832
Chet Haase7fc27ea2013-10-01 15:34:22 -0700833 private static class MyOnClickHandler extends OnClickHandler {
834
835 // weak reference to the hostView to avoid keeping a live reference
836 // due to Binder GC linkages to AppWidgetHost. By the same token,
837 // this click handler should not keep references to any large
838 // objects.
839 WeakReference<KeyguardHostView> mThis;
840
841 MyOnClickHandler(KeyguardHostView hostView) {
842 mThis = new WeakReference<KeyguardHostView>(hostView);
843 }
844
Jim Millerdcb3d842012-08-23 19:18:12 -0700845 @Override
846 public boolean onClickHandler(final View view,
847 final android.app.PendingIntent pendingIntent,
848 final Intent fillInIntent) {
Chet Haase7fc27ea2013-10-01 15:34:22 -0700849 KeyguardHostView hostView = mThis.get();
850 if (hostView == null) {
851 return false;
852 }
Jim Millerdcb3d842012-08-23 19:18:12 -0700853 if (pendingIntent.isActivity()) {
Chet Haase7fc27ea2013-10-01 15:34:22 -0700854 hostView.setOnDismissAction(new OnDismissAction() {
John Spurlock34c4fe52012-11-07 10:12:29 -0500855 public boolean onDismiss() {
Jim Millerdcb3d842012-08-23 19:18:12 -0700856 try {
Chet Haase7fc27ea2013-10-01 15:34:22 -0700857 // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
858 Context context = view.getContext();
859 ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(view,
860 0, 0,
861 view.getMeasuredWidth(), view.getMeasuredHeight());
862 context.startIntentSender(
863 pendingIntent.getIntentSender(), fillInIntent,
864 Intent.FLAG_ACTIVITY_NEW_TASK,
865 Intent.FLAG_ACTIVITY_NEW_TASK, 0, opts.toBundle());
John Spurlock34c4fe52012-11-07 10:12:29 -0500866 } catch (IntentSender.SendIntentException e) {
867 android.util.Log.e(TAG, "Cannot send pending intent: ", e);
868 } catch (Exception e) {
869 android.util.Log.e(TAG, "Cannot send pending intent due to " +
870 "unknown exception: ", e);
871 }
872 return false;
Jim Millerdcb3d842012-08-23 19:18:12 -0700873 }
Jim Miller5f75aa12012-08-29 15:10:34 -0700874 });
Jim Millerdcb3d842012-08-23 19:18:12 -0700875
Chet Haase7fc27ea2013-10-01 15:34:22 -0700876 if (hostView.mViewStateManager.isChallengeShowing()) {
877 hostView.mViewStateManager.showBouncer(true);
Jim Miller08898372012-11-04 19:08:40 -0800878 } else {
Chet Haase7fc27ea2013-10-01 15:34:22 -0700879 hostView.mCallback.dismiss(false);
Jim Miller08898372012-11-04 19:08:40 -0800880 }
Jim Millerdcb3d842012-08-23 19:18:12 -0700881 return true;
882 } else {
883 return super.onClickHandler(view, pendingIntent, fillInIntent);
884 }
885 };
886 };
887
Jim Miller63f9b812012-10-15 15:58:01 -0700888 // Used to ignore callbacks from methods that are no longer current (e.g. face unlock).
889 // This avoids unwanted asynchronous events from messing with the state.
890 private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() {
891
892 @Override
893 public void userActivity(long timeout) {
894 }
895
896 @Override
897 public void showBackupSecurity() {
898 }
899
900 @Override
John Spurlock34c4fe52012-11-07 10:12:29 -0500901 public void setOnDismissAction(OnDismissAction action) {
Jim Miller63f9b812012-10-15 15:58:01 -0700902 }
903
904 @Override
905 public void reportSuccessfulUnlockAttempt() {
906 }
907
908 @Override
909 public void reportFailedUnlockAttempt() {
910 }
911
912 @Override
913 public boolean isVerifyUnlockOnly() {
914 return false;
915 }
916
917 @Override
918 public int getFailedAttempts() {
919 return 0;
920 }
921
922 @Override
923 public void dismiss(boolean securityVerified) {
924 }
925 };
926
Jim Miller5f75aa12012-08-29 15:10:34 -0700927 /**
John Spurlock34c4fe52012-11-07 10:12:29 -0500928 * Sets an action to perform when keyguard is dismissed.
929 * @param action
Jim Miller5f75aa12012-08-29 15:10:34 -0700930 */
John Spurlock34c4fe52012-11-07 10:12:29 -0500931 protected void setOnDismissAction(OnDismissAction action) {
932 mDismissAction = action;
Jim Miller5f75aa12012-08-29 15:10:34 -0700933 }
934
Jim Millere46efc02012-09-07 16:43:51 -0700935 private KeyguardSecurityView getSecurityView(SecurityMode securityMode) {
936 final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
937 KeyguardSecurityView view = null;
938 final int children = mSecurityViewContainer.getChildCount();
Jim Millerdcb3d842012-08-23 19:18:12 -0700939 for (int child = 0; child < children; child++) {
Jim Millere46efc02012-09-07 16:43:51 -0700940 if (mSecurityViewContainer.getChildAt(child).getId() == securityViewIdForMode) {
941 view = ((KeyguardSecurityView)mSecurityViewContainer.getChildAt(child));
942 break;
Jim Millerdcb3d842012-08-23 19:18:12 -0700943 }
944 }
Jim Miller63f9b812012-10-15 15:58:01 -0700945 int layoutId = getLayoutIdFor(securityMode);
946 if (view == null && layoutId != 0) {
Jim Millere46efc02012-09-07 16:43:51 -0700947 final LayoutInflater inflater = LayoutInflater.from(mContext);
Jim Millerbdffd5c2012-10-15 22:11:52 -0700948 if (DEBUG) Log.v(TAG, "inflating id = " + layoutId);
Adam Powell97997142012-11-06 21:32:42 -0800949 View v = inflater.inflate(layoutId, mSecurityViewContainer, false);
Jim Millere46efc02012-09-07 16:43:51 -0700950 mSecurityViewContainer.addView(v);
951 updateSecurityView(v);
Jim Miller0b728242012-10-28 19:42:30 -0700952 view = (KeyguardSecurityView)v;
Jim Millere46efc02012-09-07 16:43:51 -0700953 }
Jim Miller0ff7f012012-10-11 20:40:01 -0700954
Jim Miller0ff7f012012-10-11 20:40:01 -0700955 if (view instanceof KeyguardSelectorView) {
956 KeyguardSelectorView selectorView = (KeyguardSelectorView) view;
957 View carrierText = selectorView.findViewById(R.id.keyguard_selector_fade_container);
958 selectorView.setCarrierArea(carrierText);
959 }
Jim Miller68c24892012-10-14 05:04:00 -0700960
Jim Millere46efc02012-09-07 16:43:51 -0700961 return view;
Jim Millerdcb3d842012-08-23 19:18:12 -0700962 }
963
Jim Miller258341c2012-08-30 16:50:10 -0700964 /**
965 * Switches to the given security view unless it's already being shown, in which case
966 * this is a no-op.
967 *
Jim Millere46efc02012-09-07 16:43:51 -0700968 * @param securityMode
Jim Miller258341c2012-08-30 16:50:10 -0700969 */
Jim Millere46efc02012-09-07 16:43:51 -0700970 private void showSecurityScreen(SecurityMode securityMode) {
Jim Miller68c24892012-10-14 05:04:00 -0700971 if (DEBUG) Log.d(TAG, "showSecurityScreen(" + securityMode + ")");
972
Jim Millere46efc02012-09-07 16:43:51 -0700973 if (securityMode == mCurrentSecuritySelection) return;
Jim Millerdcb3d842012-08-23 19:18:12 -0700974
Jim Millere46efc02012-09-07 16:43:51 -0700975 KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection);
976 KeyguardSecurityView newView = getSecurityView(securityMode);
Jim Millerdcb3d842012-08-23 19:18:12 -0700977
Jim Millera71984f2012-10-24 22:08:49 -0700978 // Enter full screen mode if we're in SIM or Account screen
Jim Miller5ecd8112013-01-09 18:50:26 -0800979 boolean fullScreenEnabled = getResources().getBoolean(R.bool.kg_sim_puk_account_full_screen);
Jim Millera71984f2012-10-24 22:08:49 -0700980 boolean isSimOrAccount = securityMode == SecurityMode.SimPin
981 || securityMode == SecurityMode.SimPuk
982 || securityMode == SecurityMode.Account;
983 mAppWidgetContainer.setVisibility(
984 isSimOrAccount && fullScreenEnabled ? View.GONE : View.VISIBLE);
985
Jim Miller9c993bd2013-10-07 17:12:27 -0700986 // Don't show camera or search in navbar when SIM or Account screen is showing
987 setSystemUiVisibility(isSimOrAccount ?
988 (getSystemUiVisibility() | View.STATUS_BAR_DISABLE_SEARCH)
989 : (getSystemUiVisibility() & ~View.STATUS_BAR_DISABLE_SEARCH));
990
Jim Miller2cacda52012-11-07 22:40:20 -0800991 if (mSlidingChallengeLayout != null) {
992 mSlidingChallengeLayout.setChallengeInteractive(!fullScreenEnabled);
993 }
994
Jim Millerdcb3d842012-08-23 19:18:12 -0700995 // Emulate Activity life cycle
Jim Miller63f9b812012-10-15 15:58:01 -0700996 if (oldView != null) {
997 oldView.onPause();
998 oldView.setKeyguardCallback(mNullCallback); // ignore requests from old view
999 }
Chris Wrena042ac92012-11-07 11:37:06 -05001000 newView.onResume(KeyguardSecurityView.VIEW_REVEALED);
Jim Miller63f9b812012-10-15 15:58:01 -07001001 newView.setKeyguardCallback(mCallback);
Jim Millerdcb3d842012-08-23 19:18:12 -07001002
Craig Mautnercd03a262012-09-28 11:54:09 -07001003 final boolean needsInput = newView.needsInput();
Craig Mautner7def1db2012-09-28 10:27:56 -07001004 if (mViewMediatorCallback != null) {
Craig Mautnercd03a262012-09-28 11:54:09 -07001005 mViewMediatorCallback.setNeedsInput(needsInput);
Craig Mautner7def1db2012-09-28 10:27:56 -07001006 }
Jim Millerdcb3d842012-08-23 19:18:12 -07001007
1008 // Find and show this child.
Jim Millere46efc02012-09-07 16:43:51 -07001009 final int childCount = mSecurityViewContainer.getChildCount();
Jim Miller4b09dd32012-09-04 14:27:25 -07001010
Jim Millere46efc02012-09-07 16:43:51 -07001011 final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
Jim Millerdcb3d842012-08-23 19:18:12 -07001012 for (int i = 0; i < childCount; i++) {
Jim Millere46efc02012-09-07 16:43:51 -07001013 if (mSecurityViewContainer.getChildAt(i).getId() == securityViewIdForMode) {
1014 mSecurityViewContainer.setDisplayedChild(i);
Jim Millerdcb3d842012-08-23 19:18:12 -07001015 break;
1016 }
1017 }
Jim Miller258341c2012-08-30 16:50:10 -07001018
Jim Millere46efc02012-09-07 16:43:51 -07001019 if (securityMode == SecurityMode.None) {
Jim Millere23ab8b2012-09-16 15:45:44 -07001020 // Discard current runnable if we're switching back to the selector view
John Spurlock34c4fe52012-11-07 10:12:29 -05001021 setOnDismissAction(null);
Jim Miller68c24892012-10-14 05:04:00 -07001022 }
John Spurlock03eca852013-03-14 14:21:04 -04001023 if (securityMode == SecurityMode.Account && !mLockPatternUtils.isPermanentlyLocked()) {
1024 // we're showing account as a backup, provide a way to get back to primary
1025 setBackButtonEnabled(true);
1026 }
Jim Millere46efc02012-09-07 16:43:51 -07001027 mCurrentSecuritySelection = securityMode;
Jim Millerdcb3d842012-08-23 19:18:12 -07001028 }
1029
1030 @Override
1031 public void onScreenTurnedOn() {
John Spurlock358148e2012-10-26 15:29:59 -04001032 if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode()));
Jim Miller0ff7f012012-10-11 20:40:01 -07001033 showPrimarySecurityScreen(false);
Chris Wrena042ac92012-11-07 11:37:06 -05001034 getSecurityView(mCurrentSecuritySelection).onResume(KeyguardSecurityView.SCREEN_ON);
Jim Millerd03a5552012-09-10 20:46:36 -07001035
1036 // This is a an attempt to fix bug 7137389 where the device comes back on but the entire
1037 // layout is blank but forcing a layout causes it to reappear (e.g. with with
1038 // hierarchyviewer).
1039 requestLayout();
Adam Cohen6fb841f2012-10-24 13:15:38 -07001040
1041 if (mViewStateManager != null) {
1042 mViewStateManager.showUsabilityHints();
1043 }
Sandeep Siddharthaeec83dc2013-09-04 14:59:59 -07001044
Jim Miller147f9562012-12-03 17:55:16 -08001045 requestFocus();
Jim Millerdcb3d842012-08-23 19:18:12 -07001046 }
1047
1048 @Override
1049 public void onScreenTurnedOff() {
John Spurlockdbe24b72012-11-01 13:01:05 -04001050 if (DEBUG) Log.d(TAG, String.format("screen off, instance %s at %s",
1051 Integer.toHexString(hashCode()), SystemClock.uptimeMillis()));
Brian Colonna078f5912012-10-31 20:03:18 -04001052 // Once the screen turns off, we no longer consider this to be first boot and we want the
1053 // biometric unlock to start next time keyguard is shown.
1054 KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true);
Michael Jurka14138892012-11-07 13:45:53 -08001055 // We use mAppWidgetToShow to show a particular widget after you add it-- once the screen
1056 // turns off we reset that behavior
1057 clearAppWidgetToShow();
Jim Miller9ccf1232013-10-10 22:23:07 -07001058 if (KeyguardUpdateMonitor.getInstance(mContext).hasBootCompleted()) {
1059 checkAppWidgetConsistency();
1060 }
Jim Miller0ff7f012012-10-11 20:40:01 -07001061 showPrimarySecurityScreen(true);
Jim Millere46efc02012-09-07 16:43:51 -07001062 getSecurityView(mCurrentSecuritySelection).onPause();
John Spurlockdbe24b72012-11-01 13:01:05 -04001063 CameraWidgetFrame cameraPage = findCameraPage();
1064 if (cameraPage != null) {
1065 cameraPage.onScreenTurnedOff();
1066 }
Sandeep Siddharthaeec83dc2013-09-04 14:59:59 -07001067
Jim Miller147f9562012-12-03 17:55:16 -08001068 clearFocus();
Jim Millerdcb3d842012-08-23 19:18:12 -07001069 }
1070
Michael Jurka14138892012-11-07 13:45:53 -08001071 public void clearAppWidgetToShow() {
1072 mAppWidgetToShow = AppWidgetManager.INVALID_APPWIDGET_ID;
1073 }
1074
Jim Millerdcb3d842012-08-23 19:18:12 -07001075 @Override
1076 public void show() {
Jim Miller08697702012-10-22 16:49:52 -07001077 if (DEBUG) Log.d(TAG, "show()");
1078 showPrimarySecurityScreen(false);
Jim Millerdcb3d842012-08-23 19:18:12 -07001079 }
1080
Jim Millerdcb3d842012-08-23 19:18:12 -07001081 @Override
1082 public void verifyUnlock() {
1083 SecurityMode securityMode = mSecurityModel.getSecurityMode();
1084 if (securityMode == KeyguardSecurityModel.SecurityMode.None) {
Craig Mautner7def1db2012-09-28 10:27:56 -07001085 if (mViewMediatorCallback != null) {
1086 mViewMediatorCallback.keyguardDone(true);
1087 }
Jim Millerdcb3d842012-08-23 19:18:12 -07001088 } else if (securityMode != KeyguardSecurityModel.SecurityMode.Pattern
Daniel Sandler69bdee72012-10-23 16:45:50 -04001089 && securityMode != KeyguardSecurityModel.SecurityMode.PIN
Jim Millerdcb3d842012-08-23 19:18:12 -07001090 && securityMode != KeyguardSecurityModel.SecurityMode.Password) {
1091 // can only verify unlock when in pattern/password mode
Craig Mautner7def1db2012-09-28 10:27:56 -07001092 if (mViewMediatorCallback != null) {
1093 mViewMediatorCallback.keyguardDone(false);
1094 }
Jim Millerdcb3d842012-08-23 19:18:12 -07001095 } else {
1096 // otherwise, go to the unlock screen, see if they can verify it
1097 mIsVerifyUnlockOnly = true;
Jim Millere46efc02012-09-07 16:43:51 -07001098 showSecurityScreen(securityMode);
Jim Millerdcb3d842012-08-23 19:18:12 -07001099 }
1100 }
1101
1102 private int getSecurityViewIdForMode(SecurityMode securityMode) {
1103 switch (securityMode) {
Jim Millere46efc02012-09-07 16:43:51 -07001104 case None: return R.id.keyguard_selector_view;
1105 case Pattern: return R.id.keyguard_pattern_view;
Daniel Sandler69bdee72012-10-23 16:45:50 -04001106 case PIN: return R.id.keyguard_pin_view;
Jim Millere46efc02012-09-07 16:43:51 -07001107 case Password: return R.id.keyguard_password_view;
1108 case Biometric: return R.id.keyguard_face_unlock_view;
1109 case Account: return R.id.keyguard_account_view;
1110 case SimPin: return R.id.keyguard_sim_pin_view;
1111 case SimPuk: return R.id.keyguard_sim_puk_view;
Jim Millerdcb3d842012-08-23 19:18:12 -07001112 }
1113 return 0;
1114 }
1115
Jim Millere46efc02012-09-07 16:43:51 -07001116 private int getLayoutIdFor(SecurityMode securityMode) {
1117 switch (securityMode) {
1118 case None: return R.layout.keyguard_selector_view;
1119 case Pattern: return R.layout.keyguard_pattern_view;
Daniel Sandler69bdee72012-10-23 16:45:50 -04001120 case PIN: return R.layout.keyguard_pin_view;
Jim Millere46efc02012-09-07 16:43:51 -07001121 case Password: return R.layout.keyguard_password_view;
1122 case Biometric: return R.layout.keyguard_face_unlock_view;
1123 case Account: return R.layout.keyguard_account_view;
1124 case SimPin: return R.layout.keyguard_sim_pin_view;
1125 case SimPuk: return R.layout.keyguard_sim_puk_view;
1126 default:
Jim Miller63f9b812012-10-15 15:58:01 -07001127 return 0;
Jim Millere46efc02012-09-07 16:43:51 -07001128 }
1129 }
1130
Jim Miller51117262012-11-04 17:58:09 -08001131 private boolean addWidget(int appId, int pageIndex, boolean updateDbIfFailed) {
Michael Jurka67a871d2012-11-01 18:26:01 -07001132 AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appId);
Jim Miller99a3cae2012-09-17 20:53:51 -07001133 if (appWidgetInfo != null) {
Jim Millera75a8832013-02-07 16:53:32 -08001134 AppWidgetHostView view = mAppWidgetHost.createView(mContext, appId, appWidgetInfo);
Jim Millerd6523da2012-10-21 16:47:02 -07001135 addWidget(view, pageIndex);
Michael Jurka67a871d2012-11-01 18:26:01 -07001136 return true;
Jim Miller99a3cae2012-09-17 20:53:51 -07001137 } else {
Jim Miller51117262012-11-04 17:58:09 -08001138 if (updateDbIfFailed) {
Jim Millera75a8832013-02-07 16:53:32 -08001139 Log.w(TAG, "*** AppWidgetInfo for app widget id " + appId + " was null for user"
1140 + mUserId + ", deleting");
Jim Miller51117262012-11-04 17:58:09 -08001141 mAppWidgetHost.deleteAppWidgetId(appId);
1142 mLockPatternUtils.removeAppWidget(appId);
1143 }
Michael Jurka67a871d2012-11-01 18:26:01 -07001144 return false;
Jim Miller99a3cae2012-09-17 20:53:51 -07001145 }
Jim Millerdcb3d842012-08-23 19:18:12 -07001146 }
1147
John Spurlockdcc96812012-10-25 14:35:19 -04001148 private final CameraWidgetFrame.Callbacks mCameraWidgetCallbacks =
1149 new CameraWidgetFrame.Callbacks() {
1150 @Override
1151 public void onLaunchingCamera() {
John Spurlock57f928f2012-11-02 13:09:25 -04001152 setSliderHandleAlpha(0);
John Spurlockdcc96812012-10-25 14:35:19 -04001153 }
1154
1155 @Override
John Spurlock57f928f2012-11-02 13:09:25 -04001156 public void onCameraLaunchedSuccessfully() {
Winson Chung6cf53bb2012-11-05 17:55:42 -08001157 if (mAppWidgetContainer.isCameraPage(mAppWidgetContainer.getCurrentPage())) {
John Spurlock4b976ea2012-10-28 12:34:11 -04001158 mAppWidgetContainer.scrollLeft();
1159 }
John Spurlock57f928f2012-11-02 13:09:25 -04001160 setSliderHandleAlpha(1);
Jim Milleraaf9b112012-10-31 19:44:56 -07001161 mShowSecurityWhenReturn = true;
John Spurlockdcc96812012-10-25 14:35:19 -04001162 }
1163
John Spurlock57f928f2012-11-02 13:09:25 -04001164 @Override
1165 public void onCameraLaunchedUnsuccessfully() {
1166 setSliderHandleAlpha(1);
1167 }
1168
1169 private void setSliderHandleAlpha(float alpha) {
1170 SlidingChallengeLayout slider =
1171 (SlidingChallengeLayout) findViewById(R.id.sliding_layout);
1172 if (slider != null) {
1173 slider.setHandleAlpha(alpha);
1174 }
John Spurlockdcc96812012-10-25 14:35:19 -04001175 }
1176 };
1177
1178 private final KeyguardActivityLauncher mActivityLauncher = new KeyguardActivityLauncher() {
1179 @Override
1180 Context getContext() {
1181 return mContext;
1182 }
1183
1184 @Override
1185 KeyguardSecurityCallback getCallback() {
1186 return mCallback;
1187 }
1188
1189 @Override
1190 LockPatternUtils getLockPatternUtils() {
1191 return mLockPatternUtils;
Jim Millerbdca3c02012-10-29 19:11:50 -07001192 }
1193 };
John Spurlockdcc96812012-10-25 14:35:19 -04001194
Michael Jurkaeb963f02012-11-08 00:32:29 -08001195 private int numWidgets() {
1196 final int childCount = mAppWidgetContainer.getChildCount();
1197 int widgetCount = 0;
1198 for (int i = 0; i < childCount; i++) {
1199 if (mAppWidgetContainer.isWidgetPage(i)) {
1200 widgetCount++;
1201 }
1202 }
1203 return widgetCount;
1204 }
1205
Jim Miller4e81bd42012-10-01 20:21:02 -07001206 private void addDefaultWidgets() {
Jim Millerf45bb402013-08-20 18:58:32 -07001207 if (!mSafeModeEnabled && !widgetsDisabled()) {
Jim Miller8f09fd22013-03-14 19:04:28 -07001208 LayoutInflater inflater = LayoutInflater.from(mContext);
Jim Miller51117262012-11-04 17:58:09 -08001209 View addWidget = inflater.inflate(R.layout.keyguard_add_widget, this, false);
Michael Jurkaeb963f02012-11-08 00:32:29 -08001210 mAppWidgetContainer.addWidget(addWidget, 0);
Jim Miller51117262012-11-04 17:58:09 -08001211 View addWidgetButton = addWidget.findViewById(R.id.keyguard_add_widget_view);
1212 addWidgetButton.setOnClickListener(new OnClickListener() {
1213 @Override
1214 public void onClick(View v) {
Michael Jurka192d6d42012-11-07 01:09:38 -08001215 // Pass in an invalid widget id... the picker will allocate an ID for us
1216 mActivityLauncher.launchWidgetPicker(AppWidgetManager.INVALID_APPWIDGET_ID);
Jim Miller51117262012-11-04 17:58:09 -08001217 }
1218 });
1219 }
1220
1221 // We currently disable cameras in safe mode because we support loading 3rd party
1222 // cameras we can't trust. TODO: plumb safe mode into camera creation code and only
1223 // inflate system-provided camera?
John Spurlock371f3402012-11-30 09:20:43 -05001224 if (!mSafeModeEnabled && !cameraDisabledByDpm() && mUserSetupCompleted
Jim Miller51117262012-11-04 17:58:09 -08001225 && mContext.getResources().getBoolean(R.bool.kg_enable_camera_default_widget)) {
John Spurlockdcc96812012-10-25 14:35:19 -04001226 View cameraWidget =
1227 CameraWidgetFrame.create(mContext, mCameraWidgetCallbacks, mActivityLauncher);
1228 if (cameraWidget != null) {
1229 mAppWidgetContainer.addWidget(cameraWidget);
1230 }
John Spurlock86b63572012-10-24 11:24:25 -04001231 }
Jim Miller7221d3a2012-10-05 14:34:47 -07001232 }
1233
Jim Miller8f09fd22013-03-14 19:04:28 -07001234 /**
1235 * Create KeyguardTransportControlView on demand.
1236 * @return
1237 */
Jim Miller4894a012013-04-03 15:23:55 -07001238 private KeyguardTransportControlView getOrCreateTransportControl() {
Jim Miller8f09fd22013-03-14 19:04:28 -07001239 if (mTransportControl == null) {
1240 LayoutInflater inflater = LayoutInflater.from(mContext);
1241 mTransportControl = (KeyguardTransportControlView)
1242 inflater.inflate(R.layout.keyguard_transport_control_view, this, false);
Adam Powellf8895242013-09-30 16:16:24 -07001243 mTransportControl.setTransportControlCallback(new TransportControlCallback() {
1244 public void userActivity() {
1245 mViewMediatorCallback.userActivity();
1246 }
1247 });
Jim Millerbdca3c02012-10-29 19:11:50 -07001248 }
Jim Miller8f09fd22013-03-14 19:04:28 -07001249 return mTransportControl;
Jim Miller4e81bd42012-10-01 20:21:02 -07001250 }
1251
Jim Miller51117262012-11-04 17:58:09 -08001252 private int getInsertPageIndex() {
Michael Jurka67a871d2012-11-01 18:26:01 -07001253 View addWidget = mAppWidgetContainer.findViewById(R.id.keyguard_add_widget);
Jim Miller51117262012-11-04 17:58:09 -08001254 int insertionIndex = mAppWidgetContainer.indexOfChild(addWidget);
1255 if (insertionIndex < 0) {
1256 insertionIndex = 0; // no add widget page found
1257 } else {
1258 insertionIndex++; // place after add widget
Michael Jurka67a871d2012-11-01 18:26:01 -07001259 }
Jim Miller51117262012-11-04 17:58:09 -08001260 return insertionIndex;
Michael Jurka67a871d2012-11-01 18:26:01 -07001261 }
1262
1263 private void addDefaultStatusWidget(int index) {
1264 LayoutInflater inflater = LayoutInflater.from(mContext);
1265 View statusWidget = inflater.inflate(R.layout.keyguard_status_view, null, true);
1266 mAppWidgetContainer.addWidget(statusWidget, index);
1267 }
1268
Michael Jurka1254f2f2012-10-25 11:44:31 -07001269 private void addWidgetsFromSettings() {
Jim Millerf45bb402013-08-20 18:58:32 -07001270 if (mSafeModeEnabled || widgetsDisabled()) {
Jim Miller2ec4ff42013-08-28 17:41:16 -07001271 addDefaultStatusWidget(0);
Jim Miller51117262012-11-04 17:58:09 -08001272 return;
Jim Millerb8ec4702012-08-31 17:19:10 -07001273 }
Jim Millerf229e4d2012-09-12 20:32:50 -07001274
Jim Miller51117262012-11-04 17:58:09 -08001275 int insertionIndex = getInsertPageIndex();
Michael Jurka20c41d52012-09-20 19:01:06 -07001276
1277 // Add user-selected widget
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001278 final int[] widgets = mLockPatternUtils.getAppWidgets();
Michael Jurka67a871d2012-11-01 18:26:01 -07001279
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001280 if (widgets == null) {
1281 Log.d(TAG, "Problem reading widgets");
1282 } else {
1283 for (int i = widgets.length -1; i >= 0; i--) {
Michael Jurka1254f2f2012-10-25 11:44:31 -07001284 if (widgets[i] == LockPatternUtils.ID_DEFAULT_STATUS_WIDGET) {
Jim Miller51117262012-11-04 17:58:09 -08001285 addDefaultStatusWidget(insertionIndex);
Michael Jurka1254f2f2012-10-25 11:44:31 -07001286 } else {
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001287 // We add the widgets from left to right, starting after the first page after
1288 // the add page. We count down, since the order will be persisted from right
1289 // to left, starting after camera.
Jim Miller51117262012-11-04 17:58:09 -08001290 addWidget(widgets[i], insertionIndex, true);
Michael Jurkaaa2859a2012-10-24 12:46:49 -07001291 }
Jim Millerdcb3d842012-08-23 19:18:12 -07001292 }
1293 }
Jim Miller51117262012-11-04 17:58:09 -08001294 }
1295
1296 private int allocateIdForDefaultAppWidget() {
1297 int appWidgetId;
1298 Resources res = getContext().getResources();
1299 ComponentName defaultAppWidget = new ComponentName(
1300 res.getString(R.string.widget_default_package_name),
1301 res.getString(R.string.widget_default_class_name));
1302
1303 // Note: we don't support configuring the widget
1304 appWidgetId = mAppWidgetHost.allocateAppWidgetId();
1305
1306 try {
1307 mAppWidgetManager.bindAppWidgetId(appWidgetId, defaultAppWidget);
Jim Miller51117262012-11-04 17:58:09 -08001308 } catch (IllegalArgumentException e) {
1309 Log.e(TAG, "Error when trying to bind default AppWidget: " + e);
1310 mAppWidgetHost.deleteAppWidgetId(appWidgetId);
1311 appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
1312 }
1313 return appWidgetId;
Michael Jurka67a871d2012-11-01 18:26:01 -07001314 }
Jim Millerf45bb402013-08-20 18:58:32 -07001315
Michael Jurka67a871d2012-11-01 18:26:01 -07001316 public void checkAppWidgetConsistency() {
1317 final int childCount = mAppWidgetContainer.getChildCount();
1318 boolean widgetPageExists = false;
1319 for (int i = 0; i < childCount; i++) {
Jim Miller51117262012-11-04 17:58:09 -08001320 if (mAppWidgetContainer.isWidgetPage(i)) {
Michael Jurka67a871d2012-11-01 18:26:01 -07001321 widgetPageExists = true;
1322 break;
1323 }
1324 }
1325 if (!widgetPageExists) {
Jim Miller51117262012-11-04 17:58:09 -08001326 final int insertPageIndex = getInsertPageIndex();
Michael Jurka67a871d2012-11-01 18:26:01 -07001327
Jim Millerf45bb402013-08-20 18:58:32 -07001328 final boolean userAddedWidgetsEnabled = !widgetsDisabled();
1329
Jim Miller51117262012-11-04 17:58:09 -08001330 boolean addedDefaultAppWidget = false;
Michael Jurka67a871d2012-11-01 18:26:01 -07001331
Jim Miller51117262012-11-04 17:58:09 -08001332 if (!mSafeModeEnabled) {
1333 if (userAddedWidgetsEnabled) {
1334 int appWidgetId = allocateIdForDefaultAppWidget();
1335 if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
1336 addedDefaultAppWidget = addWidget(appWidgetId, insertPageIndex, true);
1337 }
1338 } else {
1339 // note: even if widgetsDisabledByDpm() returns true, we still bind/create
1340 // the default appwidget if possible
1341 int appWidgetId = mLockPatternUtils.getFallbackAppWidgetId();
1342 if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
1343 appWidgetId = allocateIdForDefaultAppWidget();
1344 if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
1345 mLockPatternUtils.writeFallbackAppWidgetId(appWidgetId);
1346 }
1347 }
1348 if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
1349 addedDefaultAppWidget = addWidget(appWidgetId, insertPageIndex, false);
1350 if (!addedDefaultAppWidget) {
1351 mAppWidgetHost.deleteAppWidgetId(appWidgetId);
1352 mLockPatternUtils.writeFallbackAppWidgetId(
1353 AppWidgetManager.INVALID_APPWIDGET_ID);
1354 }
1355 }
1356 }
Michael Jurka67a871d2012-11-01 18:26:01 -07001357 }
Jim Miller51117262012-11-04 17:58:09 -08001358
Michael Jurka67a871d2012-11-01 18:26:01 -07001359 // Use the built-in status/clock view if we can't inflate the default widget
Jim Miller51117262012-11-04 17:58:09 -08001360 if (!addedDefaultAppWidget) {
1361 addDefaultStatusWidget(insertPageIndex);
Michael Jurka67a871d2012-11-01 18:26:01 -07001362 }
Jim Miller51117262012-11-04 17:58:09 -08001363
1364 // trigger DB updates only if user-added widgets are enabled
1365 if (!mSafeModeEnabled && userAddedWidgetsEnabled) {
1366 mAppWidgetContainer.onAddView(
1367 mAppWidgetContainer.getChildAt(insertPageIndex), insertPageIndex);
1368 }
Michael Jurka67a871d2012-11-01 18:26:01 -07001369 }
Adam Cohen0207c092012-09-30 16:11:00 -07001370 }
1371
Jim Miller81190be2013-11-05 18:17:59 -08001372 private final Runnable mSwitchPageRunnable = new Runnable() {
Jim Miller223ce5c2012-10-05 19:13:23 -07001373 @Override
1374 public void run() {
1375 showAppropriateWidgetPage();
Adam Cohen0207c092012-09-30 16:11:00 -07001376 }
Jim Miller223ce5c2012-10-05 19:13:23 -07001377 };
1378
1379 static class SavedState extends BaseSavedState {
1380 int transportState;
Michael Jurka14138892012-11-07 13:45:53 -08001381 int appWidgetToShow = AppWidgetManager.INVALID_APPWIDGET_ID;
John Spurlock256ae672013-09-26 12:14:33 -04001382 Rect insets = new Rect();
Jim Miller223ce5c2012-10-05 19:13:23 -07001383
1384 SavedState(Parcelable superState) {
1385 super(superState);
1386 }
1387
1388 private SavedState(Parcel in) {
1389 super(in);
1390 this.transportState = in.readInt();
Michael Jurka14138892012-11-07 13:45:53 -08001391 this.appWidgetToShow = in.readInt();
John Spurlock256ae672013-09-26 12:14:33 -04001392 this.insets = in.readParcelable(null);
Jim Miller223ce5c2012-10-05 19:13:23 -07001393 }
1394
1395 @Override
1396 public void writeToParcel(Parcel out, int flags) {
1397 super.writeToParcel(out, flags);
1398 out.writeInt(this.transportState);
Michael Jurka14138892012-11-07 13:45:53 -08001399 out.writeInt(this.appWidgetToShow);
John Spurlock256ae672013-09-26 12:14:33 -04001400 out.writeParcelable(insets, 0);
Jim Miller223ce5c2012-10-05 19:13:23 -07001401 }
1402
1403 public static final Parcelable.Creator<SavedState> CREATOR
1404 = new Parcelable.Creator<SavedState>() {
1405 public SavedState createFromParcel(Parcel in) {
1406 return new SavedState(in);
1407 }
1408
1409 public SavedState[] newArray(int size) {
1410 return new SavedState[size];
1411 }
1412 };
1413 }
1414
1415 @Override
1416 public Parcelable onSaveInstanceState() {
Jim Miller4894a012013-04-03 15:23:55 -07001417 if (DEBUG) Log.d(TAG, "onSaveInstanceState, tstate=" + mTransportState);
Jim Miller223ce5c2012-10-05 19:13:23 -07001418 Parcelable superState = super.onSaveInstanceState();
1419 SavedState ss = new SavedState(superState);
Jim Miller4894a012013-04-03 15:23:55 -07001420 // If the transport is showing, force it to show it on restore.
1421 final boolean showing = mTransportControl != null
1422 && mAppWidgetContainer.getWidgetPageIndex(mTransportControl) >= 0;
1423 ss.transportState = showing ? TRANSPORT_VISIBLE : mTransportState;
Michael Jurka14138892012-11-07 13:45:53 -08001424 ss.appWidgetToShow = mAppWidgetToShow;
John Spurlock256ae672013-09-26 12:14:33 -04001425 ss.insets.set(mInsets);
Jim Miller223ce5c2012-10-05 19:13:23 -07001426 return ss;
1427 }
1428
1429 @Override
1430 public void onRestoreInstanceState(Parcelable state) {
1431 if (!(state instanceof SavedState)) {
1432 super.onRestoreInstanceState(state);
1433 return;
1434 }
1435 SavedState ss = (SavedState) state;
1436 super.onRestoreInstanceState(ss.getSuperState());
Jim Miller8f09fd22013-03-14 19:04:28 -07001437 mTransportState = (ss.transportState);
Michael Jurka14138892012-11-07 13:45:53 -08001438 mAppWidgetToShow = ss.appWidgetToShow;
John Spurlock256ae672013-09-26 12:14:33 -04001439 setInsets(ss.insets);
Jim Miller4894a012013-04-03 15:23:55 -07001440 if (DEBUG) Log.d(TAG, "onRestoreInstanceState, transport=" + mTransportState);
Jim Miller81190be2013-11-05 18:17:59 -08001441 mSwitchPageRunnable.run();
Jim Miller223ce5c2012-10-05 19:13:23 -07001442 }
1443
John Spurlock5f050e52012-10-27 10:44:19 -04001444 @Override
John Spurlock256ae672013-09-26 12:14:33 -04001445 protected boolean fitSystemWindows(Rect insets) {
1446 setInsets(insets);
1447 return true;
1448 }
1449
1450 private void setInsets(Rect insets) {
1451 mInsets.set(insets);
1452 if (mSlidingChallengeLayout != null) mSlidingChallengeLayout.setInsets(mInsets);
1453 if (mMultiPaneChallengeLayout != null) mMultiPaneChallengeLayout.setInsets(mInsets);
Daniel Sandler26b7bf62013-10-10 12:44:12 -04001454
1455 final CameraWidgetFrame cameraWidget = findCameraPage();
1456 if (cameraWidget != null) cameraWidget.setInsets(mInsets);
John Spurlock256ae672013-09-26 12:14:33 -04001457 }
1458
1459 @Override
John Spurlock5f050e52012-10-27 10:44:19 -04001460 public void onWindowFocusChanged(boolean hasWindowFocus) {
1461 super.onWindowFocusChanged(hasWindowFocus);
1462 if (DEBUG) Log.d(TAG, "Window is " + (hasWindowFocus ? "focused" : "unfocused"));
Michael Jurka76017ca2012-11-06 16:21:09 -08001463 if (hasWindowFocus && mShowSecurityWhenReturn) {
Jim Milleraaf9b112012-10-31 19:44:56 -07001464 SlidingChallengeLayout slider =
1465 (SlidingChallengeLayout) findViewById(R.id.sliding_layout);
1466 if (slider != null) {
1467 slider.setHandleAlpha(1);
1468 slider.showChallenge(true);
1469 }
1470 mShowSecurityWhenReturn = false;
John Spurlock5f050e52012-10-27 10:44:19 -04001471 }
1472 }
1473
Jim Miller4d20ed32013-10-19 01:00:16 +00001474 private void showAppropriateWidgetPage() {
Jim Miller81190be2013-11-05 18:17:59 -08001475 final int state = mTransportState;
1476 final boolean transportAdded = ensureTransportPresentOrRemoved(state);
1477 final int pageToShow = getAppropriateWidgetPage(state);
1478 if (!transportAdded) {
1479 mAppWidgetContainer.setCurrentPage(pageToShow);
1480 } else if (state == TRANSPORT_VISIBLE) {
1481 // If the transport was just added, we need to wait for layout to happen before
1482 // we can set the current page.
1483 post(new Runnable() {
1484 @Override
1485 public void run() {
1486 mAppWidgetContainer.setCurrentPage(pageToShow);
1487 }
1488 });
1489 }
Jim Millerdcb3d842012-08-23 19:18:12 -07001490 }
1491
Jim Miller4894a012013-04-03 15:23:55 -07001492 /**
1493 * Examines the current state and adds the transport to the widget pager when the state changes.
1494 *
1495 * Showing the initial transport and keeping it around is a bit tricky because the signals
1496 * coming from music players aren't always clear. Here's how the states are handled:
1497 *
1498 * {@link TRANSPORT_GONE} means we have no reason to show the transport - remove it if present.
1499 *
1500 * {@link TRANSPORT_INVISIBLE} means we have potential to show the transport because a music
1501 * player is registered but not currently playing music (or we don't know the state yet). The
1502 * code adds it conditionally on play state.
1503 *
1504 * {@link #TRANSPORT_VISIBLE} means a music player is active and transport should be showing.
1505 *
1506 * Once the transport is showing, we always show it until keyguard is dismissed. This state is
1507 * maintained by onSave/RestoreInstanceState(). This state is cleared in
1508 * {@link KeyguardViewManager#hide} when keyguard is dismissed, which causes the transport to be
1509 * gone when keyguard is restarted until we get an update with the current state.
1510 *
1511 * @param state
1512 */
Jim Miller81190be2013-11-05 18:17:59 -08001513 private boolean ensureTransportPresentOrRemoved(int state) {
Jim Miller4894a012013-04-03 15:23:55 -07001514 final boolean showing = getWidgetPosition(R.id.keyguard_transport_control) != -1;
1515 final boolean visible = state == TRANSPORT_VISIBLE;
1516 final boolean shouldBeVisible = state == TRANSPORT_INVISIBLE && isMusicPlaying(state);
1517 if (!showing && (visible || shouldBeVisible)) {
Jim Miller4894a012013-04-03 15:23:55 -07001518 // insert to left of camera if it exists, otherwise after right-most widget
1519 int lastWidget = mAppWidgetContainer.getChildCount() - 1;
1520 int position = 0; // handle no widget case
1521 if (lastWidget >= 0) {
1522 position = mAppWidgetContainer.isCameraPage(lastWidget) ?
1523 lastWidget : lastWidget + 1;
Jim Miller8f09fd22013-03-14 19:04:28 -07001524 }
Jim Miller81190be2013-11-05 18:17:59 -08001525 if (DEBUGXPORT) Log.v(TAG, "add transport at " + position);
Jim Miller4894a012013-04-03 15:23:55 -07001526 mAppWidgetContainer.addWidget(getOrCreateTransportControl(), position);
Jim Miller81190be2013-11-05 18:17:59 -08001527 return true;
Jim Miller4894a012013-04-03 15:23:55 -07001528 } else if (showing && state == TRANSPORT_GONE) {
Jim Miller8f09fd22013-03-14 19:04:28 -07001529 if (DEBUGXPORT) Log.v(TAG, "remove transport");
Jim Miller4894a012013-04-03 15:23:55 -07001530 mAppWidgetContainer.removeWidget(getOrCreateTransportControl());
Jim Miller8f09fd22013-03-14 19:04:28 -07001531 mTransportControl = null;
Adam Powell43a372f2013-09-27 17:43:53 -07001532 KeyguardUpdateMonitor.getInstance(getContext()).dispatchSetBackground(null);
Jim Miller8f09fd22013-03-14 19:04:28 -07001533 }
Jim Miller81190be2013-11-05 18:17:59 -08001534 return false;
Jim Miller8f09fd22013-03-14 19:04:28 -07001535 }
1536
John Spurlockdbe24b72012-11-01 13:01:05 -04001537 private CameraWidgetFrame findCameraPage() {
1538 for (int i = mAppWidgetContainer.getChildCount() - 1; i >= 0; i--) {
Winson Chung6cf53bb2012-11-05 17:55:42 -08001539 if (mAppWidgetContainer.isCameraPage(i)) {
John Spurlockdbe24b72012-11-01 13:01:05 -04001540 return (CameraWidgetFrame) mAppWidgetContainer.getChildAt(i);
1541 }
1542 }
1543 return null;
1544 }
1545
Winson Chung6cf53bb2012-11-05 17:55:42 -08001546 boolean isMusicPage(int pageIndex) {
1547 return pageIndex >= 0 && pageIndex == getWidgetPosition(R.id.keyguard_transport_control);
1548 }
1549
Jim Miller8f09fd22013-03-14 19:04:28 -07001550 private int getAppropriateWidgetPage(int musicTransportState) {
John Spurlock358148e2012-10-26 15:29:59 -04001551 // assumes at least one widget (besides camera + add)
Michael Jurka76017ca2012-11-06 16:21:09 -08001552 if (mAppWidgetToShow != AppWidgetManager.INVALID_APPWIDGET_ID) {
1553 final int childCount = mAppWidgetContainer.getChildCount();
1554 for (int i = 0; i < childCount; i++) {
1555 if (mAppWidgetContainer.getWidgetPageAt(i).getContentAppWidgetId()
1556 == mAppWidgetToShow) {
Michael Jurka76017ca2012-11-06 16:21:09 -08001557 return i;
1558 }
1559 }
1560 mAppWidgetToShow = AppWidgetManager.INVALID_APPWIDGET_ID;
1561 }
John Spurlock358148e2012-10-26 15:29:59 -04001562 // if music playing, show transport
Jim Miller8f09fd22013-03-14 19:04:28 -07001563 if (musicTransportState == TRANSPORT_VISIBLE) {
John Spurlock358148e2012-10-26 15:29:59 -04001564 if (DEBUG) Log.d(TAG, "Music playing, show transport");
Jim Miller4894a012013-04-03 15:23:55 -07001565 return mAppWidgetContainer.getWidgetPageIndex(getOrCreateTransportControl());
John Spurlock358148e2012-10-26 15:29:59 -04001566 }
1567
John Spurlock5f050e52012-10-27 10:44:19 -04001568 // else show the right-most widget (except for camera)
John Spurlock358148e2012-10-26 15:29:59 -04001569 int rightMost = mAppWidgetContainer.getChildCount() - 1;
Winson Chung6cf53bb2012-11-05 17:55:42 -08001570 if (mAppWidgetContainer.isCameraPage(rightMost)) {
John Spurlock358148e2012-10-26 15:29:59 -04001571 rightMost--;
1572 }
John Spurlock5f050e52012-10-27 10:44:19 -04001573 if (DEBUG) Log.d(TAG, "Show right-most page " + rightMost);
John Spurlock358148e2012-10-26 15:29:59 -04001574 return rightMost;
1575 }
1576
Jim Miller19a52672012-10-23 19:52:04 -07001577 private void enableUserSelectorIfNecessary() {
Jim Miller26e6c2e2012-10-30 14:12:22 -07001578 if (!UserManager.supportsMultipleUsers()) {
1579 return; // device doesn't support multi-user mode
1580 }
Jim Millerf6ab5f92012-11-07 16:15:13 -08001581 final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
Chris Wrend2dec002012-11-07 16:38:33 -05001582 if (um == null) {
1583 Throwable t = new Throwable();
1584 t.fillInStackTrace();
1585 Log.e(TAG, "user service is null.", t);
1586 return;
1587 }
Jim Miller26e6c2e2012-10-30 14:12:22 -07001588
John Spurlock5f050e52012-10-27 10:44:19 -04001589 // if there are multiple users, we need to enable to multi-user switcher
Jim Millerf6ab5f92012-11-07 16:15:13 -08001590 final List<UserInfo> users = um.getUsers(true);
Chris Wrend2dec002012-11-07 16:38:33 -05001591 if (users == null) {
1592 Throwable t = new Throwable();
1593 t.fillInStackTrace();
1594 Log.e(TAG, "list of users is null.", t);
1595 return;
1596 }
Adam Cohen66b9fb1662012-09-05 16:23:58 -07001597
Jim Millerf6ab5f92012-11-07 16:15:13 -08001598 final View multiUserView = findViewById(R.id.keyguard_user_selector);
1599 if (multiUserView == null) {
1600 Throwable t = new Throwable();
1601 t.fillInStackTrace();
1602 Log.e(TAG, "can't find user_selector in layout.", t);
1603 return;
1604 }
1605
Chris Wrend2dec002012-11-07 16:38:33 -05001606 if (users.size() > 1) {
Chris Wren91f080c2012-11-07 15:20:27 -05001607 if (multiUserView instanceof KeyguardMultiUserSelectorView) {
Chris Wrenf41c61b2012-11-29 15:19:54 -05001608 mKeyguardMultiUserSelectorView = (KeyguardMultiUserSelectorView) multiUserView;
1609 mKeyguardMultiUserSelectorView.setVisibility(View.VISIBLE);
1610 mKeyguardMultiUserSelectorView.addUsers(users);
Chris Wren91f080c2012-11-07 15:20:27 -05001611 UserSwitcherCallback callback = new UserSwitcherCallback() {
1612 @Override
1613 public void hideSecurityView(int duration) {
1614 mSecurityViewContainer.animate().alpha(0).setDuration(duration);
Jim Miller0ff7f012012-10-11 20:40:01 -07001615 }
Adam Cohen0a8d3262012-10-03 13:50:55 -07001616
Chris Wren91f080c2012-11-07 15:20:27 -05001617 @Override
1618 public void showSecurityView() {
1619 mSecurityViewContainer.setAlpha(1.0f);
Jim Miller19a52672012-10-23 19:52:04 -07001620 }
Chris Wren91f080c2012-11-07 15:20:27 -05001621
1622 @Override
1623 public void showUnlockHint() {
1624 if (mKeyguardSelectorView != null) {
1625 mKeyguardSelectorView.showUsabilityHint();
1626 }
1627 }
1628
1629 @Override
1630 public void userActivity() {
1631 if (mViewMediatorCallback != null) {
1632 mViewMediatorCallback.userActivity();
1633 }
1634 }
1635 };
Chris Wrenf41c61b2012-11-29 15:19:54 -05001636 mKeyguardMultiUserSelectorView.setCallback(callback);
Chris Wrend2dec002012-11-07 16:38:33 -05001637 } else {
1638 Throwable t = new Throwable();
1639 t.fillInStackTrace();
1640 if (multiUserView == null) {
1641 Log.e(TAG, "could not find the user_selector.", t);
1642 } else {
1643 Log.e(TAG, "user_selector is the wrong type.", t);
1644 }
Chris Wren91f080c2012-11-07 15:20:27 -05001645 }
Adam Cohen66b9fb1662012-09-05 16:23:58 -07001646 }
1647 }
1648
Jim Millerdcb3d842012-08-23 19:18:12 -07001649 @Override
1650 public void cleanUp() {
Adam Cohen128f2762013-04-18 13:37:05 -07001651 // Make sure we let go of all widgets and their package contexts promptly. If we don't do
1652 // this, and the associated application is uninstalled, it can cause a soft reboot.
1653 int count = mAppWidgetContainer.getChildCount();
1654 for (int i = 0; i < count; i++) {
1655 KeyguardWidgetFrame frame = mAppWidgetContainer.getWidgetPageAt(i);
1656 frame.removeAllViews();
1657 }
Jim Millerdcb3d842012-08-23 19:18:12 -07001658 }
1659
Jim Miller95b005c2012-08-29 16:43:32 -07001660 /**
1661 * In general, we enable unlocking the insecure keyguard with the menu key. However, there are
1662 * some cases where we wish to disable it, notably when the menu button placement or technology
1663 * is prone to false positives.
1664 *
1665 * @return true if the menu key should be enabled
1666 */
1667 private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key";
1668 private boolean shouldEnableMenuKey() {
1669 final Resources res = getResources();
Jim Miller5ecd8112013-01-09 18:50:26 -08001670 final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen);
Jim Miller95b005c2012-08-29 16:43:32 -07001671 final boolean isTestHarness = ActivityManager.isRunningInTestHarness();
1672 final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists();
1673 return !configDisabled || isTestHarness || fileOverride;
1674 }
1675
Michael Jurka76017ca2012-11-06 16:21:09 -08001676 public void goToWidget(int appWidgetId) {
1677 mAppWidgetToShow = appWidgetId;
1678 mSwitchPageRunnable.run();
1679 }
1680
Jim Miller75931e02012-11-02 16:39:22 -07001681 public boolean handleMenuKey() {
1682 // The following enables the MENU key to work for testing automation
1683 if (shouldEnableMenuKey()) {
1684 showNextSecurityScreenOrFinish(false);
1685 return true;
1686 }
1687 return false;
1688 }
1689
Jim Miller0a34d9e2012-10-05 17:15:41 -07001690 public boolean handleBackKey() {
John Spurlock03eca852013-03-14 14:21:04 -04001691 if (mCurrentSecuritySelection == SecurityMode.Account) {
1692 // go back to primary screen and re-disable back
1693 setBackButtonEnabled(false);
1694 showPrimarySecurityScreen(false /*turningOff*/);
1695 return true;
1696 }
Jim Miller0a34d9e2012-10-05 17:15:41 -07001697 if (mCurrentSecuritySelection != SecurityMode.None) {
1698 mCallback.dismiss(false);
1699 return true;
1700 }
1701 return false;
1702 }
1703
Craig Mautnerad09bcc2012-10-08 13:33:11 -07001704 /**
1705 * Dismisses the keyguard by going to the next screen or making it gone.
1706 */
1707 public void dismiss() {
1708 showNextSecurityScreenOrFinish(false);
1709 }
Jim Miller4eeb4f62012-11-08 00:04:29 -08001710
1711 public void showAssistant() {
1712 final Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
Dianne Hackbornf9c5e0f2013-01-23 14:39:13 -08001713 .getAssistIntent(mContext, true, UserHandle.USER_CURRENT);
Jim Miller4eeb4f62012-11-08 00:04:29 -08001714
1715 if (intent == null) return;
1716
1717 final ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
1718 R.anim.keyguard_action_assist_enter, R.anim.keyguard_action_assist_exit,
1719 getHandler(), null);
1720
1721 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Jim Miller4eeb4f62012-11-08 00:04:29 -08001722
Daniel Sandler6ed3fca2012-11-08 09:58:27 -05001723 mActivityLauncher.launchActivityWithAnimation(
1724 intent, false, opts.toBundle(), null, null);
Jim Miller4eeb4f62012-11-08 00:04:29 -08001725 }
Jim Millercaf24fc2013-09-10 18:37:01 -07001726
1727 public void dispatch(MotionEvent event) {
1728 mAppWidgetContainer.handleExternalCameraEvent(event);
1729 }
1730
Jim Miller138f25d2013-09-25 13:46:58 -07001731 public void launchCamera() {
1732 mActivityLauncher.launchCamera(getHandler(), null);
1733 }
1734
Jim Millerdcb3d842012-08-23 19:18:12 -07001735}